Passed
Push — weight_redistributor ( af2cc6...92270a )
by Doug
02:00
created

ItemList::insertFromArray()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Box packing (3D bin packing, knapsack problem).
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace DVDoug\BoxPacker;
10
11
use ArrayIterator;
12
use Countable;
13
use IteratorAggregate;
14
use Traversable;
15
16
/**
17
 * List of items to be packed, ordered by volume.
18
 *
19
 * @author Doug Wright
20
 */
21
class ItemList implements Countable, IteratorAggregate
22
{
23
    /**
24
     * List containing items.
25
     *
26
     * @var Item[]
27
     */
28
    private $list = [];
29
30
    /**
31
     * Has this list already been sorted?
32
     *
33
     * @var bool
34
     */
35
    private $isSorted = false;
36
37
    /**
38
     * @param Item $item
39
     */
40 25
    public function insert(Item $item)
41
    {
42 25
        $this->list[] = $item;
43 25
    }
44
45
    /**
46
     * Do a bulk insert.
47
     *
48
     * @internal
49
     *
50
     * @param Item[] $items
51
     */
52 5
    public function insertFromArray(array $items): void
53
    {
54 5
        foreach ($items as $item) {
55 1
            $this->insert($item);
56
        }
57 5
    }
58
59
    /**
60
     * @internal
61
     *
62
     * @return Item
63
     */
64 21
    public function extract(): Item
65
    {
66 21
        if (!$this->isSorted) {
67 21
            usort($this->list, [$this, 'compare']);
68 21
            $this->isSorted = true;
69
        }
70
71 21
        return array_shift($this->list);
72
    }
73
74
    /**
75
     * @internal
76
     *
77
     * @return Item
78
     */
79 20
    public function top(): Item
80
    {
81 20
        if (!$this->isSorted) {
82 1
            usort($this->list, [$this, 'compare']);
83 1
            $this->isSorted = true;
84
        }
85 20
        $temp = $this->list;
86
87 20
        return reset($temp);
88
    }
89
90
    /**
91
     * @return Traversable
92
     */
93 7
    public function getIterator(): Traversable
94
    {
95 7
        if (!$this->isSorted) {
96 7
            usort($this->list, [$this, 'compare']);
97 7
            $this->isSorted = true;
98
        }
99
100 7
        return new ArrayIterator($this->list);
101
    }
102
103
    /**
104
     * Number of items in list.
105
     *
106
     * @return int
107
     */
108 23
    public function count(): int
109
    {
110 23
        return count($this->list);
111
    }
112
113
    /**
114
     * @param Item $itemA
115
     * @param Item $itemB
116
     *
117
     * @return int
118
     */
119 21
    private function compare(Item $itemA, Item $itemB): int
120
    {
121 21
        $itemAVolume = $itemA->getWidth() * $itemA->getLength() * $itemA->getDepth();
122 21
        $itemBVolume = $itemB->getWidth() * $itemB->getLength() * $itemB->getDepth();
123 21
        $volumeDecider = $itemBVolume <=> $itemAVolume;
124 21
        $weightDecider = $itemB->getWeight() - $itemA->getWeight();
125 21
        if ($volumeDecider !== 0) {
126 12
            return $volumeDecider;
127 19
        } elseif ($weightDecider !== 0) {
128 3
            return $weightDecider;
129
        } else {
130 16
            return $itemA->getDescription() <=> $itemB->getDescription();
131
        }
132
    }
133
}
134