Completed
Push — master ( cb5f1c...5f5111 )
by Victor
03:46
created

Truncator::pad()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 13
c 0
b 0
f 0
nc 5
nop 3
dl 0
loc 17
rs 8.8333
1
<?php
2
3
namespace Vctls\IntervalGraph;
4
5
6
use InvalidArgumentException;
7
8
/**
9
 * Truncate an array of intervals according to a low and high bound.
10
 *
11
 * @package Vctls\IntervalGraph
12
 */
13
class Truncator
14
{
15
    /**
16
     * Truncate all intervals to the given lower and upper limits.
17
     *
18
     * @param array $intervals
19
     * @param mixed $lowerLimit
20
     * @param mixed $upperLimit
21
     * @param bool $padding Add null value intervals between the bounds and the first and last bounds.
22
     * @return array
23
     */
24
    public static function truncate(array $intervals, $lowerLimit = null, $upperLimit = null, $padding = false): array
25
    {
26
        $limits = [
27
            0 => $lowerLimit,
28
            1 => $upperLimit
29
        ];
30
        foreach ($limits as $type => $limit) {
31
            if (isset($limit)) {
32
                foreach ($intervals as $key => $interval) {
33
                    if (self::compareToLimit($interval[$type], $limit, $type)) {
34
                        if (self::compareToLimit($interval[(int)!$type], $limit, $type)) {
35
                            // If both bounds are beyond the limit, set the interval to false for removal.
36
                            $intervals[$key] = false;
37
                        } else {
38
                            // If only the outer bound is beyond the limit, set it to the limit value.
39
                            $intervals[$key][$type] = $limit;
40
                        }
41
                    }
42
                }
43
44
                // Remove false elements.
45
                $intervals = array_filter($intervals);
46
47
                // If padding is required and a limit is set and is beyond the limit,
48
                // add a valueless interval between that bound and the limit.
49
                if ($padding) {
50
                    self::pad($intervals, $limit, $type);
51
                }
52
            }
53
        }
54
55
        return $intervals;
56
    }
57
58
    /**
59
     * Pad the interval array if needed, from left OR right depending on the type.
60
     *
61
     * @param $intervals
62
     * @param $value
63
     * @param $type
64
     */
65
    public static function pad(&$intervals, $value, $type): void
66
    {
67
        switch ($type) {
68
            case 0:
69
                $bound = self::minBound($intervals);
70
                if (isset($bound) && $bound > $value) {
71
                    array_unshift($intervals, [$value, $bound]);
72
                }
73
                break;
74
            case 1:
75
                $bound = self::maxBound($intervals);
76
                if (isset($bound) && $bound < $value) {
77
                    $intervals[] = [$bound, $value];
78
                }
79
                break;
80
            default:
81
                throw new InvalidArgumentException('Type should be 0 (low padding) or 1 (high padding).');
82
        }
83
    }
84
85
    /**
86
     * Return the minimum or maximum bound depending on the type.
87
     *
88
     * @param $intervals
89
     * @param int $type 0 (min) or 1 (max)
90
     * @return mixed
91
     */
92
    public static function outerBound($intervals, int $type)
93
    {
94
        switch ($type) {
95
            case 0:
96
                return self::minBound($intervals);
97
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
98
            case 1:
99
                return self::maxBound($intervals);
100
                break;
101
            default:
102
                throw new InvalidArgumentException('Type must be 0 (min) or 1 (max)');
103
        }
104
    }
105
106
    /**
107
     * Get the minimum bound in an array of intervals.
108
     *
109
     * @param $intervals
110
     * @return mixed
111
     */
112
    public static function minBound($intervals)
113
    {
114
        $bounds = array_column($intervals, 0);
115
        sort($bounds);
116
        return array_shift($bounds);
117
    }
118
119
    /**
120
     * Get the maximum bound in an array of intervals.
121
     *
122
     * @param $intervals
123
     * @return mixed
124
     */
125
    public static function maxBound($intervals)
126
    {
127
        $bounds = array_column($intervals, 1);
128
        sort($bounds);
129
        return array_pop($bounds);
130
    }
131
132
    /**
133
     * Checks if the value is inferior to a lower (type 0) limit,
134
     * or superior to an upper (type 1) limit.
135
     *
136
     * @param $value
137
     * @param $limit
138
     * @param int $type 0 (lower limit) or 1 (upper limit)
139
     * @return bool
140
     */
141
    private static function compareToLimit($value, $limit, int $type): bool
142
    {
143
        switch ($type) {
144
            case 0 :
145
                return $value < $limit;
146
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
147
            case 1 :
148
                return $value > $limit;
149
                break;
150
            default :
151
                throw new InvalidArgumentException('Limit type must be 0 (lower) or 1 (upper)');
152
        }
153
    }
154
}
155