• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

chdemko / php-sorted-collections / 24611836123

18 Apr 2026 07:09PM UTC coverage: 98.849% (-0.5%) from 99.355%
24611836123

push

github

chdemko
🚨 Fix scrutinizer

13 of 17 new or added lines in 1 file covered. (76.47%)

773 of 782 relevant lines covered (98.85%)

113.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.54
/src/SortedCollection/SubSet.php
1
<?php
2

3
/**
4
 * chdemko\SortedCollection\SubSet class
5
 *
6
 * @author    Christophe Demko <chdemko@gmail.com>
7
 * @copyright Copyright (C) 2012-2024 Christophe Demko. All rights reserved.
8
 *
9
 * @license BSD 3-Clause License
10
 *
11
 * This file is part of the php-sorted-collections package https://github.com/chdemko/php-sorted-collections
12
 */
13

14
// Declare chdemko\SortedCollection namespace
15
namespace chdemko\SortedCollection;
16

17
/**
18
 * Sub set
19
 *
20
 * @package    SortedCollection
21
 * @subpackage Set
22
 *
23
 * @since 1.0.0
24
 *
25
 * @property      mixed      $from           The from element
26
 * @property      boolean    $fromInclusive  The from inclusive flag
27
 * @property      mixed      $to             The to element
28
 * @property      boolean    $toInclusive    The to inclusive flag
29
 * @property-read callable   $comparator     The element comparison function
30
 * @property-read mixed      $first          The first element of the set
31
 * @property-read mixed      $last           The last element of the set
32
 * @property-read integer    $count          The number of elements in the set
33
 * @property-read SortedSet  $set            The underlying set
34
 */
35
class SubSet extends AbstractSet
36
{
37
    /**
38
     * When the from or to value is unused
39
     *
40
     * @since 1.0.0
41
     */
42
    private const UNUSED = 0;
43

44
    /**
45
     * When the from or to value is inclusive
46
     *
47
     * @since 1.0.0
48
     */
49
    private const INCLUSIVE = 1;
50

51
    /**
52
     * When the from or to value is exclusive
53
     *
54
     * @since 1.0.0
55
     */
56
    private const EXCLUSIVE = 2;
57

58
    /**
59
     * @var SortedSet  Internal set
60
     *
61
     * @since 1.0.0
62
     */
63
    private $setInternal;
64

65
    /**
66
     * Resolve the underlying map for a sorted set
67
     *
68
     * @param SortedSet $set Internal set
69
     *
70
     * @return SortedMap The underlying map
71
     *
72
     * @since 1.0.0
73
     */
74
    private function resolveMap(SortedSet $set)
75
    {
76
        if ($set instanceof AbstractSet) {
20✔
77
            return $set->getMap();
20✔
78
        }
79

NEW
80
        $map = TreeMap::create($set->comparator());
×
81

NEW
82
        foreach ($set as $value) {
×
NEW
83
            $map[$value] = true;
×
84
        }
85

NEW
86
        return $map;
×
87
    }
88

89
    /**
90
     * Get the underlying map as a SubMap
91
     *
92
     * @throws RuntimeException If the underlying map is not a SubMap
93
     *
94
     * @return SubMap The underlying sub map
95
     *
96
     * @since 1.0.0
97
     */
98
    private function getSubMap()
99
    {
100
        $map = $this->getMap();
11✔
101

102
        if (!$map instanceof SubMap) {
11✔
103
            throw new \RuntimeException('Unexpected map type');
×
104
        }
105

106
        return $map;
11✔
107
    }
108

109
    /**
110
     * Magic get method
111
     *
112
     * @param string $property The property
113
     *
114
     * @return mixed The value associated to the property
115
     *
116
     * @since 1.0.0
117
     */
118
    public function __get($property)
119
    {
120
        $map = $this->getSubMap();
9✔
121

122
        switch ($property) {
123
            case 'from':
9✔
124
                return $map->fromKey;
8✔
125
            case 'to':
9✔
126
                return $map->toKey;
8✔
127
            case 'fromInclusive':
9✔
128
                return $map->fromInclusive;
8✔
129
            case 'toInclusive':
8✔
130
                return $map->toInclusive;
8✔
131
            case 'set':
1✔
132
                return $this->setInternal;
1✔
133
            default:
134
                return parent::__get($property);
1✔
135
        }
136
    }
137

138
    /**
139
     * Magic set method
140
     *
141
     * @param string $property The property
142
     * @param mixed  $value    The new value
143
     *
144
     * @throws RuntimeException If the property does not exist
145
     *
146
     * @return void
147
     *
148
     * @since 1.0.0
149
     */
150
    public function __set($property, $value)
151
    {
152
        $map = $this->getSubMap();
1✔
153

154
        switch ($property) {
155
            case 'from':
1✔
156
                $map->fromKey = $value;
1✔
157
                break;
1✔
158
            case 'to':
1✔
159
                $map->toKey = $value;
1✔
160
                break;
1✔
161
            case 'fromInclusive':
1✔
162
                $map->fromInclusive = $value;
1✔
163
                break;
1✔
164
            case 'toInclusive':
1✔
165
                $map->toInclusive = $value;
1✔
166
                break;
1✔
167
            default:
168
                throw new \RuntimeException('Undefined property');
1✔
169
        }
170
    }
171

172
    /**
173
     * Magic unset method
174
     *
175
     * @param string $property The property
176
     *
177
     * @throws RuntimeException If the property does not exist
178
     *
179
     * @return void
180
     *
181
     * @since 1.0.0
182
     */
183
    public function __unset($property)
184
    {
185
        $map = $this->getSubMap();
1✔
186

187
        switch ($property) {
188
            case 'from':
1✔
189
                unset($map->fromKey);
1✔
190
                break;
1✔
191
            case 'to':
1✔
192
                unset($map->toKey);
1✔
193
                break;
1✔
194
            case 'fromInclusive':
1✔
195
                unset($map->fromInclusive);
1✔
196
                break;
1✔
197
            case 'toInclusive':
1✔
198
                unset($map->toInclusive);
1✔
199
                break;
1✔
200
            default:
201
                throw new \RuntimeException('Undefined property');
1✔
202
        }
203
    }
204

205
    /**
206
     * Magic isset method
207
     *
208
     * @param string $property The property
209
     *
210
     * @return boolean
211
     *
212
     * @since 1.0.0
213
     */
214
    public function __isset($property)
215
    {
216
        $map = $this->getSubMap();
9✔
217

218
        switch ($property) {
219
            case 'from':
9✔
220
                return isset($map->fromKey);
9✔
221
            case 'to':
9✔
222
                return isset($map->toKey);
9✔
223
            case 'fromInclusive':
1✔
224
                return isset($map->fromInclusive);
1✔
225
            case 'toInclusive':
1✔
226
                return isset($map->toInclusive);
1✔
227
            default:
228
                return false;
1✔
229
        }
230
    }
231

232
    /**
233
     * Constructor
234
     *
235
     * @param SortedSet $set        Internal set
236
     * @param mixed     $from       The from element
237
     * @param integer   $fromOption The option for from (SubSet::UNUSED, SubSet::INCLUSIVE or SubSet::EXCLUSIVE)
238
     * @param mixed     $to         The to element
239
     * @param integer   $toOption   The option for to (SubSet::UNUSED, SubSet::INCLUSIVE or SubSet::EXCLUSIVE)
240
     *
241
     * @since 1.0.0
242
     */
243
    protected function __construct(SortedSet $set, $from, $fromOption, $to, $toOption)
244
    {
245
        $map = $this->resolveMap($set);
20✔
246

247
        if ($fromOption == self::UNUSED) {
20✔
248
            if ($toOption == self::UNUSED) {
5✔
249
                $this->setMap(SubMap::view($map));
2✔
250
            } else {
251
                $this->setMap(SubMap::head($map, $to, $toOption == self::INCLUSIVE));
3✔
252
            }
253
        } elseif ($toOption == self::UNUSED) {
15✔
254
            $this->setMap(SubMap::tail($map, $from, $fromOption == self::INCLUSIVE));
3✔
255
        } else {
256
            $this->setMap(
12✔
257
                SubMap::create($map, $from, $to, $fromOption == self::INCLUSIVE, $toOption == self::INCLUSIVE)
12✔
258
            );
12✔
259
        }
260

261
        $this->setInternal = $set;
20✔
262
    }
263

264
    /**
265
     * Create
266
     *
267
     * @param SortedSet $set           Internal set
268
     * @param mixed     $from          The from element
269
     * @param mixed     $to            The to element
270
     * @param boolean   $fromInclusive The inclusive flag for from
271
     * @param boolean   $toInclusive   The inclusive flag for to
272
     *
273
     * @return SubSet A new sub set
274
     *
275
     * @since 1.0.0
276
     */
277
    public static function create(SortedSet $set, $from, $to, $fromInclusive = true, $toInclusive = false)
278
    {
279
        return new static(
12✔
280
            $set,
12✔
281
            $from,
12✔
282
            $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE,
12✔
283
            $to,
12✔
284
            $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE
12✔
285
        );
12✔
286
    }
287

288
    /**
289
     * Head
290
     *
291
     * @param SortedSet $set         Internal set
292
     * @param mixed     $to          The to element
293
     * @param boolean   $toInclusive The inclusive flag for to
294
     *
295
     * @return SubSet A new head set
296
     *
297
     * @since 1.0.0
298
     */
299
    public static function head(SortedSet $set, $to, $toInclusive = false)
300
    {
301
        return new static($set, null, self::UNUSED, $to, $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE);
3✔
302
    }
303

304
    /**
305
     * Tail
306
     *
307
     * @param SortedSet $set           Internal set
308
     * @param mixed     $from          The from element
309
     * @param boolean   $fromInclusive The inclusive flag for from
310
     *
311
     * @return SubSet A new tail set
312
     *
313
     * @since 1.0.0
314
     */
315
    public static function tail(SortedSet $set, $from, $fromInclusive = true)
316
    {
317
        return new static($set, $from, $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE, null, self::UNUSED);
3✔
318
    }
319

320
    /**
321
     * View
322
     *
323
     * @param SortedSet $set Internal set
324
     *
325
     * @return SubSet A new sub set
326
     *
327
     * @since 1.0.0
328
     */
329
    public static function view(SortedSet $set)
330
    {
331
        return new static($set, null, self::UNUSED, null, self::UNUSED);
2✔
332
    }
333

334
    /**
335
     * Serialize the object
336
     *
337
     * @return array Array of values
338
     *
339
     * @since 1.0.0
340
     */
341
    public function jsonSerialize(): array
342
    {
343
        if (isset($this->from)) {
8✔
344
            if (isset($this->to)) {
6✔
345
                return array(
5✔
346
                    'SubSet' => array(
5✔
347
                        'set' => $this->setInternal->jsonSerialize(),
5✔
348
                        'from' => $this->from,
5✔
349
                        'fromInclusive' => $this->fromInclusive,
5✔
350
                        'to' => $this->to,
5✔
351
                        'toInclusive' => $this->toInclusive,
5✔
352
                    )
5✔
353
                );
5✔
354
            } else {
355
                return array(
1✔
356
                    'TailSet' => array(
1✔
357
                        'set' => $this->setInternal->jsonSerialize(),
1✔
358
                        'from' => $this->from,
1✔
359
                        'fromInclusive' => $this->fromInclusive,
1✔
360
                    )
1✔
361
                );
1✔
362
            }
363
        } else {
364
            if (isset($this->to)) {
2✔
365
                return array(
1✔
366
                    'HeadSet' => array(
1✔
367
                        'set' => $this->setInternal->jsonSerialize(),
1✔
368
                        'to' => $this->to,
1✔
369
                        'toInclusive' => $this->toInclusive,
1✔
370
                    )
1✔
371
                );
1✔
372
            } else {
373
                return array(
1✔
374
                    'ViewSet' => array(
1✔
375
                        'set' => $this->setInternal->jsonSerialize(),
1✔
376
                    )
1✔
377
                );
1✔
378
            }
379
        }
380
    }
381
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc