Text::readableSize()   B
last analyzed

Complexity

Conditions 7
Paths 9

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 20
c 1
b 0
f 0
nc 9
nop 3
dl 0
loc 35
rs 8.6666
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of DivineNii opensource projects.
7
 *
8
 * PHP version 7.4 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 DivineNii (https://divinenii.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace App\BenchMark\Reporter\Printer;
19
20
use App\BenchMark\Reporter\BenchMark;
21
22
class Text implements PrinterInterface
23
{
24
    protected BenchMark $benchmark;
25
26
    /**
27
     * {@inheritdoc}
28
     */
29
    public function bind(BenchMark $benchmark): void
30
    {
31
        $this->benchmark = $benchmark;
32
    }
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function chart(): string
38
    {
39
        $result    = '';
40
        $maxLength = $maxRate = 0;
41
        $ranking   = $this->benchmark->getMatrix()->ranking();
42
43
        foreach ($ranking as $task) {
44
            if ($task->failed()) {
45
                continue;
46
            }
47
48
            if ($task->rate() > $maxRate) {
49
                $maxRate = $task->rate();
50
            }
51
52
            if (\mb_strlen($task->name()) > $maxLength) {
53
                $maxLength = \mb_strlen($task->name());
54
            }
55
        }
56
57
        foreach ($ranking as $task) {
58
            $name = $task->name();
59
            $result .= $this->strPad($name, $maxLength, ' ', \STR_PAD_RIGHT);
60
61
            if ($task->failed()) {
62
                $ratio = 0;
63
                $result .= $this->strPad('x', 10);
64
            } else {
65
                $rate  = $task->rate();
66
                $ratio = ($rate / $maxRate);
67
                $result .= $this->strPad(\round($ratio * 100) . '%', 10);
68
            }
69
            $result .= ' | ';
70
71
            $width = 60;
72
            $chars = (int) ($width * $ratio);
73
            $result .= \str_repeat('█', $chars);
74
            $result .= \str_repeat(' ', $width - $chars);
75
            $result .= "  |\n";
76
        }
77
78
        return $result;
79
    }
80
81
    /**
82
     * Returns the report.
83
     *
84
     * @return string the report
85
     */
86
    public function table(): string
87
    {
88
        $ranking = $this->benchmark->getMatrix()->ranking();
89
        $matrix  = $this->benchmark->getMatrix()->matrix();
90
91
        if (!$ranking) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ranking of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
92
            return '';
93
        }
94
95
        $columnLength = [];
96
        $maxLength    = 0;
97
98
        foreach ($ranking as $task) {
99
            $name = $task->name();
100
101
            if (\preg_match('~^([\w\s]+)~', $name, $matches)) {
102
                $columnLength[$name] = \mb_strlen(\trim($matches[1]));
103
            } else {
104
                $columnLength[$name] = \mb_strlen($name);
105
            }
106
107
            if (\mb_strlen($name) > $maxLength) {
108
                $maxLength = \mb_strlen($name);
109
            }
110
        }
111
112
        $result = '';
113
        $result .= $this->strPad('', $maxLength);
114
        $result .= $this->strPad('Rate', 10);
115
        $result .= $this->strPad('Mem', 8);
116
117
        foreach ($ranking as $task) {
118
            $name = $task->name();
119
120
            if (\preg_match('~^([\w\s]+)~', $name, $matches)) {
121
                $result .= $this->strPad(\trim($matches[1]), $columnLength[$name] + 2);
122
            } else {
123
                $result .= $this->strPad($name, $columnLength[$name] + 2);
124
            }
125
        }
126
        $result .= "\n";
127
128
        foreach ($ranking as $task1) {
129
            $name1 = $task1->name();
130
            $result .= $this->strPad($name1, $maxLength, ' ', \STR_PAD_RIGHT);
131
            $task1 = $this->_benchmark->task($name1);
0 ignored issues
show
Bug introduced by
The property _benchmark does not exist on App\BenchMark\Reporter\Printer\Text. Did you mean benchmark?
Loading history...
132
133
            $result .= $this->strPad($this->readableSize($task1->rate()) . '/s', 10);
134
            $result .= $this->strPad($this->readableSize($task1->memory(), 0, 1024) . 'B', 8);
135
136
            foreach ($ranking as $task2) {
137
                $name2 = $task2->name();
138
139
                if ($task1->failed() || $task2->failed()) {
140
                    $result .= $this->strPad('x', $columnLength[$name2] + 2);
141
                } else {
142
                    $percent = $matrix[$name1][$name2] !== 100 ? $matrix[$name1][$name2] : '--';
143
                    $result .= $this->strPad($percent . '%', $columnLength[$name2] + 2);
144
                }
145
            }
146
            $result .= "\n";
147
        }
148
149
        return $result;
150
    }
151
152
    /**
153
     * Humanizes values using an appropriate unit.
154
     *
155
     * @return int    $value     the value
156
     * @return int    $precision the required precision
157
     * @return int    $base      the unit base
158
     * @return string the Humanized string value
159
     */
160
    public function readableSize($value, $precision = 0, $base = 1000): string
161
    {
162
        $i = 0;
163
164
        if (!$value) {
165
            return '0';
0 ignored issues
show
Bug Best Practice introduced by
The expression return '0' returns the type string which is incompatible with the documented return type integer.
Loading history...
166
        }
167
        $isNeg = false;
168
169
        if ($value < 0) {
170
            $isNeg = true;
171
            $value = -$value;
172
        }
173
174
        if ($value >= 1) {
175
            $units = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
176
177
            while (($value / $base) >= 1) {
178
                $value = $value / $base;
179
                $i++;
180
            }
181
182
            $unit = $units[$i] ?? '?';
183
        } else {
184
            $units = ['', 'm', 'µ', 'n', 'p', 'f', 'a', 'z'];
185
186
            while (($value * $base) <= $base) {
187
                $value = $value * $base;
188
                $i++;
189
            }
190
191
            $unit = $units[$i] ?? '?';
192
        }
193
194
        return \round($isNeg ? -$value : $value, $precision) . $unit;
0 ignored issues
show
Bug Best Practice introduced by
The expression return round($isNeg ? -$...ue, $precision) . $unit returns the type string which is incompatible with the documented return type integer.
Loading history...
195
    }
196
197
    /**
198
     * Pad a string to a certain length with another string.
199
     *
200
     * @param string $input  the input string
201
     * @param string $length the padding length
202
     * @param string $string the padding string
203
     * @param string $type   the type of padding
204
     *
205
     * @return string the padded string
206
     */
207
    public function strPad($input, $length, $string = ' ', $type = \STR_PAD_LEFT)
208
    {
209
        return \str_pad($input, $length + \strlen($input) - \mb_strlen($input), $string, $type);
0 ignored issues
show
Bug introduced by
It seems like $type can also be of type string; however, parameter $pad_type of str_pad() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

209
        return \str_pad($input, $length + \strlen($input) - \mb_strlen($input), $string, /** @scrutinizer ignore-type */ $type);
Loading history...
210
    }
211
}
212