Passed
Push — master ( d0ebb7...0d8755 )
by Rudi
03:39
created

Capacity::nextCapacity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
namespace Ds\Traits;
3
4
use Ds\Deque;
5
6
/**
7
 * Common to structures that deal with an internal capacity. While none of the
8
 * PHP implementations actually make use of a capacity, it's important to keep
9
 * consistent with the extension.
10
 */
11
trait Capacity
12
{
13
    /**
14
     * @var integer internal capacity
15
     */
16
    private $capacity = self::MIN_CAPACITY;
17
18
    /**
19
     * Returns the current capacity.
20
     *
21
     * @return int
22
     */
23
    public function capacity(): int
24
    {
25
        return $this->capacity;
26
    }
27
28
    /**
29
     * Ensures that enough memory is allocated for a specified capacity. This
30
     * potentially reduces the number of reallocations as the size increases.
31
     *
32
     * @param int $capacity The number of values for which capacity should be
33
     *                      allocated. Capacity will stay the same if this value
34
     *                      is less than or equal to the current capacity.
35
     */
36
    public function allocate(int $capacity)
37
    {
38
        $this->capacity = max($capacity, $this->capacity);
39
    }
40
41
    /**
42
     * @return float the structures growth factor.
43
     */
44
    protected function getGrowthFactor(): float
45
    {
46
        return 2;
47
    }
48
49
    /**
50
     * @return float to multiply by when decreasing capacity.
51
     */
52
    protected function getDecayFactor(): float
53
    {
54
        return 0.5;
55
    }
56
57
    /**
58
     * @return float the ratio between size and capacity when capacity should be
59
     *               decreased.
60
     */
61
    protected function getTruncateThreshold(): float
62
    {
63
        return 0.25;
64
    }
65
66
    /**
67
     * Checks and adjusts capacity if required.
68
     */
69
    protected function checkCapacity()
70
    {
71
        if ($this->shouldIncreaseCapacity()) {
72
            $this->increaseCapacity();
73
        } else {
74
            if ($this->shouldDecreaseCapacity()) {
75
                $this->decreaseCapacity();
76
            }
77
        }
78
    }
79
80
    /**
81
     * @param int $total
82
     */
83
    protected function ensureCapacity(int $total)
84
    {
85
        if ($total > $this->capacity()) {
86
            $this->capacity = max($total, $this->nextCapacity());
87
        }
88
    }
89
90
    /**
91
     * @return bool whether capacity should be increased.
92
     */
93
    protected function shouldIncreaseCapacity(): bool
94
    {
95
        return $this->count() >= $this->capacity();
0 ignored issues
show
Bug introduced by
It seems like count() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
96
    }
97
98
    protected function nextCapacity(): int
99
    {
100
        return $this->capacity() * $this->getGrowthFactor();
101
    }
102
103
    /**
104
     * Called when capacity should be increased to accommodate new values.
105
     */
106
    protected function increaseCapacity()
107
    {
108
        $this->capacity = max(
109
            $this->count(),
0 ignored issues
show
Bug introduced by
It seems like count() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
110
            $this->nextCapacity()
111
        );
112
    }
113
114
    /**
115
     * Called when capacity should be decrease if it drops below a threshold.
116
     */
117
    protected function decreaseCapacity()
118
    {
119
        $this->capacity = max(
120
            self::MIN_CAPACITY,
121
            $this->capacity()  * $this->getDecayFactor()
122
        );
123
    }
124
125
    /**
126
     * @return bool whether capacity should be increased.
127
     */
128
    protected function shouldDecreaseCapacity(): bool
129
    {
130
        return count($this) <= $this->capacity() * $this->getTruncateThreshold();
131
    }
132
}
133