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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<?php
 
namespace Ulrichsg\Collections;
 
/**
 * A map that contains only numeric values, and supports mathematical operations.
 *
 * @version 1.0.0
 * @license MIT
 */
class NumberMap extends Map {
 
    /** @internal */
    private $default;
 
    /**
     * Creates a new NumberMap with the given array as its contents. Omitting the argument creates an empty map.
     * @param array $data
     * @param mixed $default
     * @throws \InvalidArgumentException if $default or one of the array values is not numeric
     */
    public function __construct(array $data = array(), $default = 0) {
        parent::__construct();
        foreach ($data as $key => $value) {
            $this->set($key, $value);
        }
        if (is_numeric($default)) {
            $this->default = $default;
        } else {
            throw new \InvalidArgumentException("Expected number, found ".gettype($default));
        }
    }
 
    /**
     * Puts the given key-value pair into the map.
     * @param mixed $key
     * @param mixed $value
     * @throws \InvalidArgumentException if $value is not numeric
     */
    public function set($key, $value) {
        $this->assertIsNumeric($value);
        parent::set($key, $value);
    }
 
    /**
     * Adds the given value to the one associated to the given key.
     * If the key is not in the map yet, put it in and assume the map-wide default value.
     * @param mixed $key
     * @param mixed $value
     * @throws \InvalidArgumentException if $value is not numeric
     */
    public function add($key, $value) {
        $this->assertIsNumeric($value);
        $oldValue = $this->hasKey($key) ? $this->get($key) : $this->default;
        $this->set($key, $oldValue + $value);
    }
 
    /**
     * Returns the sum of all values in the map.
     * @return mixed
     */
    public function sum() {
        return array_sum($this->data);
    }
 
    /** @internal */
    private function assertIsNumeric($value) {
        if (!is_numeric($value)) {
            throw new \InvalidArgumentException("Expected number, found ".gettype($value));
        }
    }
}