Passed
Push — develop ( a0f387...0a2079 )
by Christophe
01:49
created
src/SortedCollection/SubSet.php 1 patch
Indentation   +276 added lines, -276 removed lines patch added patch discarded remove patch
@@ -34,294 +34,294 @@
 block discarded – undo
34 34
  */
35 35
 class SubSet extends AbstractSet
36 36
 {
37
-    /**
38
-     * When the from or to value is unused
39
-     *
40
-     * @since 1.0.0
41
-     */
42
-    private const UNUSED = 0;
37
+	/**
38
+	 * When the from or to value is unused
39
+	 *
40
+	 * @since 1.0.0
41
+	 */
42
+	private const UNUSED = 0;
43 43
 
44
-    /**
45
-     * When the from or to value is inclusive
46
-     *
47
-     * @since 1.0.0
48
-     */
49
-    private const INCLUSIVE = 1;
44
+	/**
45
+	 * When the from or to value is inclusive
46
+	 *
47
+	 * @since 1.0.0
48
+	 */
49
+	private const INCLUSIVE = 1;
50 50
 
51
-    /**
52
-     * When the from or to value is exclusive
53
-     *
54
-     * @since 1.0.0
55
-     */
56
-    private const EXCLUSIVE = 2;
51
+	/**
52
+	 * When the from or to value is exclusive
53
+	 *
54
+	 * @since 1.0.0
55
+	 */
56
+	private const EXCLUSIVE = 2;
57 57
 
58
-    /**
59
-     * @var SortedSet  Internal set
60
-     *
61
-     * @since 1.0.0
62
-     */
63
-    private $set;
58
+	/**
59
+	 * @var SortedSet  Internal set
60
+	 *
61
+	 * @since 1.0.0
62
+	 */
63
+	private $set;
64 64
 
65
-    /**
66
-     * Magic get method
67
-     *
68
-     * @param string $property The property
69
-     *
70
-     * @return mixed The value associated to the property
71
-     *
72
-     * @since 1.0.0
73
-     */
74
-    public function __get($property)
75
-    {
76
-        switch ($property) {
77
-            case 'from':
78
-                return $this->getMap()->fromKey;
79
-            case 'to':
80
-                return $this->getMap()->toKey;
81
-            case 'fromInclusive':
82
-                return $this->getMap()->fromInclusive;
83
-            case 'toInclusive':
84
-                return $this->getMap()->toInclusive;
85
-            case 'set':
86
-                return $this->set;
87
-            default:
88
-                return parent::__get($property);
89
-        }
90
-    }
65
+	/**
66
+	 * Magic get method
67
+	 *
68
+	 * @param string $property The property
69
+	 *
70
+	 * @return mixed The value associated to the property
71
+	 *
72
+	 * @since 1.0.0
73
+	 */
74
+	public function __get($property)
75
+	{
76
+		switch ($property) {
77
+			case 'from':
78
+				return $this->getMap()->fromKey;
79
+			case 'to':
80
+				return $this->getMap()->toKey;
81
+			case 'fromInclusive':
82
+				return $this->getMap()->fromInclusive;
83
+			case 'toInclusive':
84
+				return $this->getMap()->toInclusive;
85
+			case 'set':
86
+				return $this->set;
87
+			default:
88
+				return parent::__get($property);
89
+		}
90
+	}
91 91
 
92
-    /**
93
-     * Magic set method
94
-     *
95
-     * @param string $property The property
96
-     * @param mixed  $value    The new value
97
-     *
98
-     * @throws \RuntimeException If the property does not exist
99
-     *
100
-     * @return void
101
-     *
102
-     * @since 1.0.0
103
-     */
104
-    public function __set($property, $value)
105
-    {
106
-        switch ($property) {
107
-            case 'from':
108
-                $this->getMap()->fromKey = $value;
109
-                break;
110
-            case 'to':
111
-                $this->getMap()->toKey = $value;
112
-                break;
113
-            case 'fromInclusive':
114
-                $this->getMap()->fromInclusive = $value;
115
-                break;
116
-            case 'toInclusive':
117
-                $this->getMap()->toInclusive = $value;
118
-                break;
119
-            default:
120
-                throw new \RuntimeException('Undefined property');
121
-        }
122
-    }
92
+	/**
93
+	 * Magic set method
94
+	 *
95
+	 * @param string $property The property
96
+	 * @param mixed  $value    The new value
97
+	 *
98
+	 * @throws \RuntimeException If the property does not exist
99
+	 *
100
+	 * @return void
101
+	 *
102
+	 * @since 1.0.0
103
+	 */
104
+	public function __set($property, $value)
105
+	{
106
+		switch ($property) {
107
+			case 'from':
108
+				$this->getMap()->fromKey = $value;
109
+				break;
110
+			case 'to':
111
+				$this->getMap()->toKey = $value;
112
+				break;
113
+			case 'fromInclusive':
114
+				$this->getMap()->fromInclusive = $value;
115
+				break;
116
+			case 'toInclusive':
117
+				$this->getMap()->toInclusive = $value;
118
+				break;
119
+			default:
120
+				throw new \RuntimeException('Undefined property');
121
+		}
122
+	}
123 123
 
124
-    /**
125
-     * Magic unset method
126
-     *
127
-     * @param string $property The property
128
-     *
129
-     * @throws \RuntimeException If the property does not exist
130
-     *
131
-     * @return void
132
-     *
133
-     * @since 1.0.0
134
-     */
135
-    public function __unset($property)
136
-    {
137
-        switch ($property) {
138
-            case 'from':
139
-                unset($this->getMap()->fromKey);
140
-                break;
141
-            case 'to':
142
-                unset($this->getMap()->toKey);
143
-                break;
144
-            case 'fromInclusive':
145
-                unset($this->getMap()->fromInclusive);
146
-                break;
147
-            case 'toInclusive':
148
-                unset($this->getMap()->toInclusive);
149
-                break;
150
-            default:
151
-                throw new \RuntimeException('Undefined property');
152
-        }
153
-    }
124
+	/**
125
+	 * Magic unset method
126
+	 *
127
+	 * @param string $property The property
128
+	 *
129
+	 * @throws \RuntimeException If the property does not exist
130
+	 *
131
+	 * @return void
132
+	 *
133
+	 * @since 1.0.0
134
+	 */
135
+	public function __unset($property)
136
+	{
137
+		switch ($property) {
138
+			case 'from':
139
+				unset($this->getMap()->fromKey);
140
+				break;
141
+			case 'to':
142
+				unset($this->getMap()->toKey);
143
+				break;
144
+			case 'fromInclusive':
145
+				unset($this->getMap()->fromInclusive);
146
+				break;
147
+			case 'toInclusive':
148
+				unset($this->getMap()->toInclusive);
149
+				break;
150
+			default:
151
+				throw new \RuntimeException('Undefined property');
152
+		}
153
+	}
154 154
 
155
-    /**
156
-     * Magic isset method
157
-     *
158
-     * @param string $property The property
159
-     *
160
-     * @return boolean
161
-     *
162
-     * @since 1.0.0
163
-     */
164
-    public function __isset($property)
165
-    {
166
-        switch ($property) {
167
-            case 'from':
168
-                return isset($this->getMap()->fromKey);
169
-            case 'to':
170
-                return isset($this->getMap()->toKey);
171
-            case 'fromInclusive':
172
-                return isset($this->getMap()->fromInclusive);
173
-            case 'toInclusive':
174
-                return isset($this->getMap()->toInclusive);
175
-            default:
176
-                return false;
177
-        }
178
-    }
155
+	/**
156
+	 * Magic isset method
157
+	 *
158
+	 * @param string $property The property
159
+	 *
160
+	 * @return boolean
161
+	 *
162
+	 * @since 1.0.0
163
+	 */
164
+	public function __isset($property)
165
+	{
166
+		switch ($property) {
167
+			case 'from':
168
+				return isset($this->getMap()->fromKey);
169
+			case 'to':
170
+				return isset($this->getMap()->toKey);
171
+			case 'fromInclusive':
172
+				return isset($this->getMap()->fromInclusive);
173
+			case 'toInclusive':
174
+				return isset($this->getMap()->toInclusive);
175
+			default:
176
+				return false;
177
+		}
178
+	}
179 179
 
180
-    /**
181
-     * Constructor
182
-     *
183
-     * @param SortedSet $set        Internal set
184
-     * @param mixed     $from       The from element
185
-     * @param integer   $fromOption The option for from (SubSet::UNUSED, SubSet::INCLUSIVE or SubSet::EXCLUSIVE)
186
-     * @param mixed     $to         The to element
187
-     * @param integer   $toOption   The option for to (SubSet::UNUSED, SubSet::INCLUSIVE or SubSet::EXCLUSIVE)
188
-     *
189
-     * @since 1.0.0
190
-     */
191
-    protected function __construct(SortedSet $set, $from, $fromOption, $to, $toOption)
192
-    {
193
-        if ($fromOption == self::UNUSED) {
194
-            if ($toOption == self::UNUSED) {
195
-                $this->setMap(SubMap::view($set->getMap()));
196
-            } else {
197
-                $this->setMap(SubMap::head($set->getMap(), $to, $toOption == self::INCLUSIVE));
198
-            }
199
-        } elseif ($toOption == self::UNUSED) {
200
-            $this->setMap(SubMap::tail($set->getMap(), $from, $fromOption == self::INCLUSIVE));
201
-        } else {
202
-            $this->setMap(
203
-                SubMap::create($set->getMap(), $from, $to, $fromOption == self::INCLUSIVE, $toOption == self::INCLUSIVE)
204
-            );
205
-        }
180
+	/**
181
+	 * Constructor
182
+	 *
183
+	 * @param SortedSet $set        Internal set
184
+	 * @param mixed     $from       The from element
185
+	 * @param integer   $fromOption The option for from (SubSet::UNUSED, SubSet::INCLUSIVE or SubSet::EXCLUSIVE)
186
+	 * @param mixed     $to         The to element
187
+	 * @param integer   $toOption   The option for to (SubSet::UNUSED, SubSet::INCLUSIVE or SubSet::EXCLUSIVE)
188
+	 *
189
+	 * @since 1.0.0
190
+	 */
191
+	protected function __construct(SortedSet $set, $from, $fromOption, $to, $toOption)
192
+	{
193
+		if ($fromOption == self::UNUSED) {
194
+			if ($toOption == self::UNUSED) {
195
+				$this->setMap(SubMap::view($set->getMap()));
196
+			} else {
197
+				$this->setMap(SubMap::head($set->getMap(), $to, $toOption == self::INCLUSIVE));
198
+			}
199
+		} elseif ($toOption == self::UNUSED) {
200
+			$this->setMap(SubMap::tail($set->getMap(), $from, $fromOption == self::INCLUSIVE));
201
+		} else {
202
+			$this->setMap(
203
+				SubMap::create($set->getMap(), $from, $to, $fromOption == self::INCLUSIVE, $toOption == self::INCLUSIVE)
204
+			);
205
+		}
206 206
 
207
-        $this->set = $set;
208
-    }
207
+		$this->set = $set;
208
+	}
209 209
 
210
-    /**
211
-     * Create
212
-     *
213
-     * @param SortedSet $set           Internal set
214
-     * @param mixed     $from          The from element
215
-     * @param mixed     $to            The to element
216
-     * @param boolean   $fromInclusive The inclusive flag for from
217
-     * @param boolean   $toInclusive   The inclusive flag for to
218
-     *
219
-     * @return SubSet A new sub set
220
-     *
221
-     * @since 1.0.0
222
-     */
223
-    public static function create(SortedSet $set, $from, $to, $fromInclusive = true, $toInclusive = false)
224
-    {
225
-        return new static(
226
-            $set,
227
-            $from,
228
-            $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE,
229
-            $to,
230
-            $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE
231
-        );
232
-    }
210
+	/**
211
+	 * Create
212
+	 *
213
+	 * @param SortedSet $set           Internal set
214
+	 * @param mixed     $from          The from element
215
+	 * @param mixed     $to            The to element
216
+	 * @param boolean   $fromInclusive The inclusive flag for from
217
+	 * @param boolean   $toInclusive   The inclusive flag for to
218
+	 *
219
+	 * @return SubSet A new sub set
220
+	 *
221
+	 * @since 1.0.0
222
+	 */
223
+	public static function create(SortedSet $set, $from, $to, $fromInclusive = true, $toInclusive = false)
224
+	{
225
+		return new static(
226
+			$set,
227
+			$from,
228
+			$fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE,
229
+			$to,
230
+			$toInclusive ? self::INCLUSIVE : self::EXCLUSIVE
231
+		);
232
+	}
233 233
 
234
-    /**
235
-     * Head
236
-     *
237
-     * @param SortedSet $set         Internal set
238
-     * @param mixed     $to          The to element
239
-     * @param boolean   $toInclusive The inclusive flag for to
240
-     *
241
-     * @return SubSet A new head set
242
-     *
243
-     * @since 1.0.0
244
-     */
245
-    public static function head(SortedSet $set, $to, $toInclusive = false)
246
-    {
247
-        return new static($set, null, self::UNUSED, $to, $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE);
248
-    }
234
+	/**
235
+	 * Head
236
+	 *
237
+	 * @param SortedSet $set         Internal set
238
+	 * @param mixed     $to          The to element
239
+	 * @param boolean   $toInclusive The inclusive flag for to
240
+	 *
241
+	 * @return SubSet A new head set
242
+	 *
243
+	 * @since 1.0.0
244
+	 */
245
+	public static function head(SortedSet $set, $to, $toInclusive = false)
246
+	{
247
+		return new static($set, null, self::UNUSED, $to, $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE);
248
+	}
249 249
 
250
-    /**
251
-     * Tail
252
-     *
253
-     * @param SortedSet $set           Internal set
254
-     * @param mixed     $from          The from element
255
-     * @param boolean   $fromInclusive The inclusive flag for from
256
-     *
257
-     * @return SubSet A new tail set
258
-     *
259
-     * @since 1.0.0
260
-     */
261
-    public static function tail(SortedSet $set, $from, $fromInclusive = true)
262
-    {
263
-        return new static($set, $from, $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE, null, self::UNUSED);
264
-    }
250
+	/**
251
+	 * Tail
252
+	 *
253
+	 * @param SortedSet $set           Internal set
254
+	 * @param mixed     $from          The from element
255
+	 * @param boolean   $fromInclusive The inclusive flag for from
256
+	 *
257
+	 * @return SubSet A new tail set
258
+	 *
259
+	 * @since 1.0.0
260
+	 */
261
+	public static function tail(SortedSet $set, $from, $fromInclusive = true)
262
+	{
263
+		return new static($set, $from, $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE, null, self::UNUSED);
264
+	}
265 265
 
266
-    /**
267
-     * View
268
-     *
269
-     * @param SortedSet $set Internal set
270
-     *
271
-     * @return SubSet A new sub set
272
-     *
273
-     * @since 1.0.0
274
-     */
275
-    public static function view(SortedSet $set)
276
-    {
277
-        return new static($set, null, self::UNUSED, null, self::UNUSED);
278
-    }
266
+	/**
267
+	 * View
268
+	 *
269
+	 * @param SortedSet $set Internal set
270
+	 *
271
+	 * @return SubSet A new sub set
272
+	 *
273
+	 * @since 1.0.0
274
+	 */
275
+	public static function view(SortedSet $set)
276
+	{
277
+		return new static($set, null, self::UNUSED, null, self::UNUSED);
278
+	}
279 279
 
280
-    /**
281
-     * Serialize the object
282
-     *
283
-     * @return array Array of values
284
-     *
285
-     * @since 1.0.0
286
-     */
287
-    public function jsonSerialize()
288
-    {
289
-        if (isset($this->from)) {
290
-            if (isset($this->to)) {
291
-                return array(
292
-                    'SubSet' => array(
293
-                        'set' => $this->set->jsonSerialize(),
294
-                        'from' => $this->from,
295
-                        'fromInclusive' => $this->fromInclusive,
296
-                        'to' => $this->to,
297
-                        'toInclusive' => $this->toInclusive,
298
-                    )
299
-                );
300
-            } else {
301
-                return array(
302
-                    'TailSet' => array(
303
-                        'set' => $this->set->jsonSerialize(),
304
-                        'from' => $this->from,
305
-                        'fromInclusive' => $this->fromInclusive,
306
-                    )
307
-                );
308
-            }
309
-        } else {
310
-            if (isset($this->to)) {
311
-                return array(
312
-                    'HeadSet' => array(
313
-                        'set' => $this->set->jsonSerialize(),
314
-                        'to' => $this->to,
315
-                        'toInclusive' => $this->toInclusive,
316
-                    )
317
-                );
318
-            } else {
319
-                return array(
320
-                    'ViewSet' => array(
321
-                        'set' => $this->set->jsonSerialize(),
322
-                    )
323
-                );
324
-            }
325
-        }
326
-    }
280
+	/**
281
+	 * Serialize the object
282
+	 *
283
+	 * @return array Array of values
284
+	 *
285
+	 * @since 1.0.0
286
+	 */
287
+	public function jsonSerialize()
288
+	{
289
+		if (isset($this->from)) {
290
+			if (isset($this->to)) {
291
+				return array(
292
+					'SubSet' => array(
293
+						'set' => $this->set->jsonSerialize(),
294
+						'from' => $this->from,
295
+						'fromInclusive' => $this->fromInclusive,
296
+						'to' => $this->to,
297
+						'toInclusive' => $this->toInclusive,
298
+					)
299
+				);
300
+			} else {
301
+				return array(
302
+					'TailSet' => array(
303
+						'set' => $this->set->jsonSerialize(),
304
+						'from' => $this->from,
305
+						'fromInclusive' => $this->fromInclusive,
306
+					)
307
+				);
308
+			}
309
+		} else {
310
+			if (isset($this->to)) {
311
+				return array(
312
+					'HeadSet' => array(
313
+						'set' => $this->set->jsonSerialize(),
314
+						'to' => $this->to,
315
+						'toInclusive' => $this->toInclusive,
316
+					)
317
+				);
318
+			} else {
319
+				return array(
320
+					'ViewSet' => array(
321
+						'set' => $this->set->jsonSerialize(),
322
+					)
323
+				);
324
+			}
325
+		}
326
+	}
327 327
 }
Please login to merge, or discard this patch.
src/SortedCollection/SubMap.php 1 patch
Indentation   +787 added lines, -787 removed lines patch added patch discarded remove patch
@@ -40,791 +40,791 @@
 block discarded – undo
40 40
  */
41 41
 class SubMap extends AbstractMap
42 42
 {
43
-    /**
44
-     * When the from or to key is unused
45
-     *
46
-     * @since 1.0.0
47
-     */
48
-    private const UNUSED = 0;
49
-
50
-    /**
51
-     * When the from or to key is inclusive
52
-     *
53
-     * @since 1.0.0
54
-     */
55
-    private const INCLUSIVE = 1;
56
-
57
-    /**
58
-     * When the from or to key is exclusive
59
-     *
60
-     * @since 1.0.0
61
-     */
62
-    private const EXCLUSIVE = 2;
63
-
64
-    /**
65
-     * @var SortedMap  Internal map
66
-     *
67
-     * @since 1.0.0
68
-     */
69
-    private $map;
70
-
71
-    /**
72
-     * @var integer  from option
73
-     *
74
-     * @since 1.0.0
75
-     */
76
-    private $fromOption;
77
-
78
-    /**
79
-     * @var mixed  from key
80
-     *
81
-     * @since 1.0.0
82
-     */
83
-    private $fromKey;
84
-
85
-    /**
86
-     * @var integer  to option
87
-     *
88
-     * @since 1.0.0
89
-     */
90
-    private $toOption;
91
-
92
-    /**
93
-     * @var mixed  to key
94
-     *
95
-     * @since 1.0.0
96
-     */
97
-    private $toKey;
98
-
99
-    /**
100
-     * @var boolean  Empty flag
101
-     *
102
-     * @since 1.0.0
103
-     */
104
-    private $empty;
105
-
106
-    /**
107
-     * Magic get method
108
-     *
109
-     * @param string $property The property
110
-     *
111
-     * @throws \RuntimeException If the property does not exist
112
-     *
113
-     * @return mixed The value associated to the property
114
-     *
115
-     * @since 1.0.0
116
-     */
117
-    public function __get($property)
118
-    {
119
-        switch ($property) {
120
-            case 'fromKey':
121
-                if ($this->fromOption == self::UNUSED) {
122
-                     throw new \RuntimeException('Undefined property');
123
-                } else {
124
-                    return $this->fromKey;
125
-                }
126
-
127
-            case 'toKey':
128
-                if ($this->toOption == self::UNUSED) {
129
-                    throw new \RuntimeException('Undefined property');
130
-                } else {
131
-                    return $this->toKey;
132
-                }
133
-
134
-            case 'fromInclusive':
135
-                if ($this->fromOption == self::UNUSED) {
136
-                    throw new \RuntimeException('Undefined property');
137
-                } else {
138
-                    return $this->fromOption == self::INCLUSIVE;
139
-                }
140
-
141
-            case 'toInclusive':
142
-                if ($this->toOption == self::UNUSED) {
143
-                    throw new \RuntimeException('Undefined property');
144
-                } else {
145
-                    return $this->toOption == self::INCLUSIVE;
146
-                }
147
-
148
-            case 'map':
149
-                return $this->map;
150
-            default:
151
-                return parent::__get($property);
152
-        }
153
-    }
154
-
155
-    /**
156
-     * Magic set method
157
-     *
158
-     * @param string $property The property
159
-     * @param mixed  $value    The new value
160
-     *
161
-     * @throws \RuntimeException If the property does not exist
162
-     *
163
-     * @return void
164
-     *
165
-     * @since 1.0.0
166
-     */
167
-    public function __set($property, $value)
168
-    {
169
-        switch ($property) {
170
-            case 'fromKey':
171
-                $this->fromKey = $value;
172
-
173
-                if ($this->fromOption == self::UNUSED) {
174
-                     $this->fromOption = self::INCLUSIVE;
175
-                }
176
-                break;
177
-            case 'toKey':
178
-                $this->toKey = $value;
179
-
180
-                if ($this->toOption == self::UNUSED) {
181
-                    $this->toOption = self::EXCLUSIVE;
182
-                }
183
-                break;
184
-            case 'fromInclusive':
185
-                if ($this->fromOption == self::UNUSED) {
186
-                    throw new \RuntimeException('Undefined property');
187
-                } else {
188
-                    $this->fromOption = $value ? self::INCLUSIVE : self::EXCLUSIVE;
189
-                }
190
-                break;
191
-            case 'toInclusive':
192
-                if ($this->toOption == self::UNUSED) {
193
-                    throw new \RuntimeException('Undefined property');
194
-                } else {
195
-                    $this->toOption = $value ? self::INCLUSIVE : self::EXCLUSIVE;
196
-                }
197
-                break;
198
-            default:
199
-                throw new \RuntimeException('Undefined property');
200
-        }
201
-
202
-        $this->setEmpty();
203
-    }
204
-
205
-    /**
206
-     * Magic unset method
207
-     *
208
-     * @param string $property The property
209
-     *
210
-     * @throws \RuntimeException If the property does not exist
211
-     *
212
-     * @return void
213
-     *
214
-     * @since 1.0.0
215
-     */
216
-    public function __unset($property)
217
-    {
218
-        switch ($property) {
219
-            case 'fromKey':
220
-            case 'fromInclusive':
221
-                $this->fromOption = self::UNUSED;
222
-                break;
223
-            case 'toKey':
224
-            case 'toInclusive':
225
-                $this->toOption = self::UNUSED;
226
-                break;
227
-            default:
228
-                throw new \RuntimeException('Undefined property');
229
-        }
230
-    }
231
-
232
-    /**
233
-     * Magic isset method
234
-     *
235
-     * @param string $property The property
236
-     *
237
-     * @return boolean
238
-     *
239
-     * @since 1.0.0
240
-     */
241
-    public function __isset($property)
242
-    {
243
-        switch ($property) {
244
-            case 'fromKey':
245
-            case 'fromInclusive':
246
-                return $this->fromOption != self::UNUSED;
247
-            case 'toKey':
248
-            case 'toInclusive':
249
-                return $this->toOption != self::UNUSED;
250
-            default:
251
-                return false;
252
-        }
253
-    }
254
-
255
-    /**
256
-     * Constructor
257
-     *
258
-     * @param SortedMap $map        Internal map
259
-     * @param mixed     $fromKey    The from key
260
-     * @param integer   $fromOption The option for from (SubMap::UNUSED, SubMap::INCLUSIVE or SubMap::EXCLUSIVE)
261
-     * @param mixed     $toKey      The to key
262
-     * @param integer   $toOption   The option for to (SubMap::UNUSED, SubMap::INCLUSIVE or SubMap::EXCLUSIVE)
263
-     *
264
-     * @since 1.0.0
265
-     */
266
-    protected function __construct(SortedMap $map, $fromKey, $fromOption, $toKey, $toOption)
267
-    {
268
-        $this->map = $map;
269
-        $this->fromKey = $fromKey;
270
-        $this->fromOption = $fromOption;
271
-        $this->toKey = $toKey;
272
-        $this->toOption = $toOption;
273
-        $this->setEmpty();
274
-    }
275
-
276
-    /**
277
-     * Set the empty flag
278
-     *
279
-     * @return void
280
-     *
281
-     * @since 1.0.0
282
-     */
283
-    protected function setEmpty()
284
-    {
285
-        if ($this->fromOption != self::UNUSED && $this->toOption != self::UNUSED) {
286
-            $cmp = call_user_func($this->map->comparator(), $this->fromKey, $this->toKey);
287
-
288
-            $this->empty = $cmp > 0
289
-              || $cmp == 0 && ($this->fromOption == self::EXCLUSIVE || $this->toOption == self::EXCLUSIVE);
290
-        } else {
291
-            $this->empty = false;
292
-        }
293
-    }
294
-
295
-    /**
296
-     * Create
297
-     *
298
-     * @param SortedMap $map           A sorted map
299
-     * @param mixed     $fromKey       The from key
300
-     * @param mixed     $toKey         The to key
301
-     * @param boolean   $fromInclusive The inclusive flag for from
302
-     * @param boolean   $toInclusive   The inclusive flag for to
303
-     *
304
-     * @return SubMap A new sub map
305
-     *
306
-     * @since 1.0.0
307
-     */
308
-    public static function create(SortedMap $map, $fromKey, $toKey, $fromInclusive = true, $toInclusive = false)
309
-    {
310
-        return new static(
311
-            $map,
312
-            $fromKey,
313
-            $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE,
314
-            $toKey,
315
-            $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE
316
-        );
317
-    }
318
-
319
-    /**
320
-     * Return a head portion of a sorted map
321
-     *
322
-     * @param SortedMap $map         A sorted map
323
-     * @param mixed     $toKey       The to key
324
-     * @param boolean   $toInclusive The inclusive flag for to
325
-     *
326
-     * @return SubMap A new head map
327
-     *
328
-     * @since 1.0.0
329
-     */
330
-    public static function head(SortedMap $map, $toKey, $toInclusive = false)
331
-    {
332
-        return new static($map, null, self::UNUSED, $toKey, $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE);
333
-    }
334
-
335
-    /**
336
-     * Return a tail portion of a sorted map
337
-     *
338
-     * @param SortedMap $map           A sorted map
339
-     * @param mixed     $fromKey       The from key
340
-     * @param boolean   $fromInclusive The inclusive flag for from
341
-     *
342
-     * @return SubMap A new tail map
343
-     *
344
-     * @since 1.0.0
345
-     */
346
-    public static function tail(SortedMap $map, $fromKey, $fromInclusive = true)
347
-    {
348
-        return new static($map, $fromKey, $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE, null, self::UNUSED);
349
-    }
350
-
351
-    /**
352
-     * Return a view of the map
353
-     *
354
-     * @param SortedMap $map A sorted map
355
-     *
356
-     * @return SubMap A new sub map
357
-     *
358
-     * @since 1.0.0
359
-     */
360
-    public static function view(SortedMap $map)
361
-    {
362
-        return new static($map, null, self::UNUSED, null, self::UNUSED);
363
-    }
364
-
365
-    /**
366
-     * Get the comparator
367
-     *
368
-     * @return callable The comparator
369
-     *
370
-     * @since 1.0.0
371
-     */
372
-    public function comparator()
373
-    {
374
-        return $this->map->comparator();
375
-    }
376
-
377
-    /**
378
-     * Get the first element
379
-     *
380
-     * @return mixed The first element
381
-     *
382
-     * @throws \OutOfBoundsException If there is no element
383
-     *
384
-     * @since 1.0.0
385
-     */
386
-    public function first()
387
-    {
388
-        if ($this->empty) {
389
-            throw new \OutOfBoundsException('First element unexisting');
390
-        }
391
-
392
-        switch ($this->fromOption) {
393
-            case self::INCLUSIVE:
394
-                $first = $this->map->ceiling($this->fromKey);
395
-                break;
396
-            case self::EXCLUSIVE:
397
-                $first = $this->map->higher($this->fromKey);
398
-                break;
399
-            default:
400
-                $first = $this->map->first();
401
-                break;
402
-        }
403
-
404
-        return $first;
405
-    }
406
-
407
-    /**
408
-     * Get the last element
409
-     *
410
-     * @return mixed The last element
411
-     *
412
-     * @throws \OutOfBoundsException If there is no element
413
-     *
414
-     * @since 1.0.0
415
-     */
416
-    public function last()
417
-    {
418
-        if ($this->empty) {
419
-            throw new \OutOfBoundsException('Last element unexisting');
420
-        }
421
-
422
-        switch ($this->toOption) {
423
-            case self::INCLUSIVE:
424
-                $last = $this->map->floor($this->toKey);
425
-                break;
426
-            case self::EXCLUSIVE:
427
-                $last = $this->map->lower($this->toKey);
428
-                break;
429
-            default:
430
-                $last = $this->map->last();
431
-                break;
432
-        }
433
-
434
-        return $last;
435
-    }
436
-
437
-    /**
438
-     * Get the predecessor element
439
-     *
440
-     * @param TreeNode $element A tree node member of the underlying TreeMap
441
-     *
442
-     * @return mixed The predecessor element
443
-     *
444
-     * @throws \OutOfBoundsException If there is no predecessor
445
-     *
446
-     * @since 1.0.0
447
-     */
448
-    public function predecessor($element)
449
-    {
450
-        $predecessor = $this->map->predecessor($element);
451
-
452
-        if ($predecessor) {
453
-            switch ($this->fromOption) {
454
-                case self::INCLUSIVE:
455
-                    if (call_user_func($this->map->comparator(), $predecessor->key, $this->fromKey) < 0) {
456
-                        throw new \OutOfBoundsException('Predecessor element unexisting');
457
-                    }
458
-                    break;
459
-                case self::EXCLUSIVE:
460
-                    if (call_user_func($this->map->comparator(), $predecessor->key, $this->fromKey) <= 0) {
461
-                        throw new \OutOfBoundsException('Predecessor element unexisting');
462
-                    }
463
-                    break;
464
-            }
465
-        }
466
-
467
-        return $predecessor;
468
-    }
469
-
470
-    /**
471
-     * Get the successor element
472
-     *
473
-     * @param TreeNode $element A tree node member of the underlying TreeMap
474
-     *
475
-     * @return mixed The successor element
476
-     *
477
-     * @throws \OutOfBoundsException If there is no successor
478
-     *
479
-     * @since 1.0.0
480
-     */
481
-    public function successor($element)
482
-    {
483
-        $successor = $this->map->successor($element);
484
-
485
-        if ($successor) {
486
-            switch ($this->toOption) {
487
-                case self::INCLUSIVE:
488
-                    if (call_user_func($this->map->comparator(), $successor->key, $this->toKey) > 0) {
489
-                        throw new \OutOfBoundsException('Successor element unexisting');
490
-                    }
491
-                    break;
492
-                case self::EXCLUSIVE:
493
-                    if (call_user_func($this->map->comparator(), $successor->key, $this->toKey) >= 0) {
494
-                        throw new \OutOfBoundsException('Successor element unexisting');
495
-                    }
496
-                    break;
497
-            }
498
-        }
499
-
500
-        return $successor;
501
-    }
502
-
503
-    /**
504
-     * Returns the element whose key is the greatest key lesser than the given key
505
-     *
506
-     * @param mixed $key The searched key
507
-     *
508
-     * @return mixed The found element
509
-     *
510
-     * @throws \OutOfBoundsException If there is no lower element
511
-     *
512
-     * @since 1.0.0
513
-     */
514
-    public function lower($key)
515
-    {
516
-        if ($this->empty) {
517
-            throw new \OutOfBoundsException('Lower element unexisting');
518
-        }
519
-
520
-        switch ($this->fromOption) {
521
-            case self::UNUSED:
522
-                $lower = $this->map->lower($key);
523
-                break;
524
-            default:
525
-                if (call_user_func($this->map->comparator(), $key, $this->fromKey) <= 0) {
526
-                    throw new \OutOfBoundsException('Lower element unexisting');
527
-                } else {
528
-                    $lower = $this->map->lower($key);
529
-
530
-                    if (
531
-                        $this->fromOption == self::EXCLUSIVE
532
-                          && call_user_func($this->map->comparator(), $lower->key, $this->fromKey) <= 0
533
-                    ) {
534
-                        throw new \OutOfBoundsException('Lower element unexisting');
535
-                    }
536
-                }
537
-                break;
538
-        }
539
-
540
-        if ($lower) {
541
-            switch ($this->toOption) {
542
-                case self::INCLUSIVE:
543
-                    if (call_user_func($this->map->comparator(), $lower->key, $this->toKey) > 0) {
544
-                          $lower = $this->last();
545
-                    }
546
-                    break;
547
-                case self::EXCLUSIVE:
548
-                    if (call_user_func($this->map->comparator(), $lower->key, $this->toKey) >= 0) {
549
-                        $lower = $this->last();
550
-                    }
551
-                    break;
552
-            }
553
-        }
554
-
555
-        return $lower;
556
-    }
557
-
558
-    /**
559
-     * Returns the element whose key is the greatest key lesser than or equal to the given key
560
-     *
561
-     * @param mixed $key The searched key
562
-     *
563
-     * @return mixed The found element
564
-     *
565
-     * @throws \OutOfBoundsException If there is no floor element
566
-     *
567
-     * @since 1.0.0
568
-     */
569
-    public function floor($key)
570
-    {
571
-        if ($this->empty) {
572
-            throw new \OutOfBoundsException('Floor element unexisting');
573
-        }
574
-
575
-        switch ($this->fromOption) {
576
-            case self::INCLUSIVE:
577
-                if (call_user_func($this->map->comparator(), $key, $this->fromKey) < 0) {
578
-                    throw new \OutOfBoundsException('Floor element unexisting');
579
-                } else {
580
-                    $floor = $this->map->floor($key);
581
-                }
582
-                break;
583
-            case self::EXCLUSIVE:
584
-                if (call_user_func($this->map->comparator(), $key, $this->fromKey) <= 0) {
585
-                    throw new \OutOfBoundsException('Floor element unexisting');
586
-                } else {
587
-                    $floor = $this->map->floor($key);
588
-                }
589
-                break;
590
-            default:
591
-                $floor = $this->map->floor($key);
592
-                break;
593
-        }
594
-
595
-        if ($floor) {
596
-            switch ($this->toOption) {
597
-                case self::INCLUSIVE:
598
-                    if (call_user_func($this->map->comparator(), $floor->key, $this->toKey) > 0) {
599
-                          $floor = $this->last();
600
-                    }
601
-                    break;
602
-                case self::EXCLUSIVE:
603
-                    if (call_user_func($this->map->comparator(), $floor->key, $this->toKey) >= 0) {
604
-                        $floor = $this->last();
605
-                    }
606
-                    break;
607
-            }
608
-        }
609
-
610
-        return $floor;
611
-    }
612
-
613
-    /**
614
-     * Returns the element whose key is equal to the given key
615
-     *
616
-     * @param mixed $key The searched key
617
-     *
618
-     * @return mixed The found element
619
-     *
620
-     * @throws \OutOfBoundsException  If there is no such element
621
-     *
622
-     * @since 1.0.0
623
-     */
624
-    public function find($key)
625
-    {
626
-        switch ($this->fromOption) {
627
-            case self::INCLUSIVE:
628
-                if (call_user_func($this->map->comparator(), $key, $this->fromKey) < 0) {
629
-                     throw new \OutOfBoundsException('Element unexisting');
630
-                }
631
-                break;
632
-            case self::EXCLUSIVE:
633
-                if (call_user_func($this->map->comparator(), $key, $this->fromKey) <= 0) {
634
-                    throw new \OutOfBoundsException('Element unexisting');
635
-                }
636
-                break;
637
-        }
638
-
639
-        switch ($this->toOption) {
640
-            case self::INCLUSIVE:
641
-                if (call_user_func($this->map->comparator(), $key, $this->toKey) > 0) {
642
-                    throw new \OutOfBoundsException('Element unexisting');
643
-                }
644
-                break;
645
-            case self::EXCLUSIVE:
646
-                if (call_user_func($this->map->comparator(), $key, $this->toKey) >= 0) {
647
-                    throw new \OutOfBoundsException('Element unexisting');
648
-                }
649
-                break;
650
-        }
651
-
652
-        return $this->map->find($key);
653
-    }
654
-
655
-    /**
656
-     * Returns the element whose key is the lowest key greater than or equal to the given key
657
-     *
658
-     * @param mixed $key The searched key
659
-     *
660
-     * @return mixed The found element
661
-     *
662
-     * @throws \OutOfBoundsException If there is no ceiling element
663
-     *
664
-     * @since 1.0.0
665
-     */
666
-    public function ceiling($key)
667
-    {
668
-        if ($this->empty) {
669
-            throw new \OutOfBoundsException('Ceiling element unexisting');
670
-        }
671
-
672
-        switch ($this->toOption) {
673
-            case self::INCLUSIVE:
674
-                if (call_user_func($this->map->comparator(), $key, $this->toKey) > 0) {
675
-                    throw new \OutOfBoundsException('Ceiling element unexisting');
676
-                } else {
677
-                    $ceiling = $this->map->ceiling($key);
678
-                }
679
-                break;
680
-            case self::EXCLUSIVE:
681
-                if (call_user_func($this->map->comparator(), $key, $this->toKey) >= 0) {
682
-                    throw new \OutOfBoundsException('Ceiling element unexisting');
683
-                } else {
684
-                    $ceiling = $this->map->ceiling($key);
685
-                }
686
-                break;
687
-            default:
688
-                $ceiling = $this->map->ceiling($key);
689
-                break;
690
-        }
691
-
692
-        if ($ceiling) {
693
-            switch ($this->fromOption) {
694
-                case self::INCLUSIVE:
695
-                    if (call_user_func($this->map->comparator(), $ceiling->key, $this->fromKey) < 0) {
696
-                          $ceiling = $this->first();
697
-                    }
698
-                    break;
699
-                case self::EXCLUSIVE:
700
-                    if (call_user_func($this->map->comparator(), $ceiling->key, $this->fromKey) <= 0) {
701
-                        $ceiling = $this->first();
702
-                    }
703
-                    break;
704
-            }
705
-        }
706
-
707
-        return $ceiling;
708
-    }
709
-
710
-    /**
711
-     * Returns the element whose key is the lowest key greater than to the given key
712
-     *
713
-     * @param mixed $key The searched key
714
-     *
715
-     * @return mixed The found element
716
-     *
717
-     * @throws \OutOfBoundsException If there is no higher element
718
-     *
719
-     * @since 1.0.0
720
-     */
721
-    public function higher($key)
722
-    {
723
-        if ($this->empty) {
724
-            throw new \OutOfBoundsException('Higher element unexisting');
725
-        }
726
-
727
-        switch ($this->toOption) {
728
-            case self::UNUSED:
729
-                $higher = $this->map->higher($key);
730
-                break;
731
-            default:
732
-                if (call_user_func($this->map->comparator(), $key, $this->toKey) >= 0) {
733
-                    throw new \OutOfBoundsException('Higher element unexisting');
734
-                } else {
735
-                    $higher = $this->map->higher($key);
736
-
737
-                    if (
738
-                        $this->toOption == self::EXCLUSIVE
739
-                          && call_user_func($this->map->comparator(), $higher->key, $this->toKey) >= 0
740
-                    ) {
741
-                        throw new \OutOfBoundsException('Higher element unexisting');
742
-                    }
743
-                }
744
-                break;
745
-        }
746
-
747
-        if ($higher) {
748
-            switch ($this->fromOption) {
749
-                case self::INCLUSIVE:
750
-                    if (call_user_func($this->map->comparator(), $higher->key, $this->fromKey) < 0) {
751
-                          $higher = $this->first();
752
-                    }
753
-                    break;
754
-                case self::EXCLUSIVE:
755
-                    if (call_user_func($this->map->comparator(), $higher->key, $this->fromKey) <= 0) {
756
-                        $higher = $this->first();
757
-                    }
758
-                    break;
759
-            }
760
-        }
761
-
762
-        return $higher;
763
-    }
764
-
765
-    /**
766
-     * Serialize the object
767
-     *
768
-     * @return array Array of values
769
-     *
770
-     * @since 1.0.0
771
-     */
772
-    public function jsonSerialize()
773
-    {
774
-        if ($this->fromOption == self::UNUSED) {
775
-            if ($this->toOption == self::UNUSED) {
776
-                return array(
777
-                    'ViewMap' => array(
778
-                        'map' => $this->map->jsonSerialize(),
779
-                     )
780
-                );
781
-            } else {
782
-                return array(
783
-                    'HeadMap' => array(
784
-                        'map' => $this->map->jsonSerialize(),
785
-                        'toKey' => $this->toKey,
786
-                        'toInclusive' => $this->toOption == self::INCLUSIVE,
787
-                    )
788
-                );
789
-            }
790
-        } else {
791
-            if ($this->toOption == self::UNUSED) {
792
-                return array(
793
-                    'TailMap' => array(
794
-                        'map' => $this->map->jsonSerialize(),
795
-                        'fromKey' => $this->fromKey,
796
-                        'fromInclusive' => $this->fromOption == self::INCLUSIVE,
797
-                    )
798
-                );
799
-            } else {
800
-                return array(
801
-                    'SubMap' => array(
802
-                        'map' => $this->map->jsonSerialize(),
803
-                        'fromKey' => $this->fromKey,
804
-                        'fromInclusive' => $this->fromOption == self::INCLUSIVE,
805
-                        'toKey' => $this->toKey,
806
-                        'toInclusive' => $this->toOption == self::INCLUSIVE,
807
-                    )
808
-                );
809
-            }
810
-        }
811
-    }
812
-
813
-    /**
814
-     * Count the number of key/value pairs
815
-     *
816
-     * @return integer
817
-     *
818
-     * @since 1.0.0
819
-     */
820
-    public function count()
821
-    {
822
-        $count = 0;
823
-
824
-        foreach ($this as $value) {
825
-            $count++;
826
-        }
827
-
828
-        return $count;
829
-    }
43
+	/**
44
+	 * When the from or to key is unused
45
+	 *
46
+	 * @since 1.0.0
47
+	 */
48
+	private const UNUSED = 0;
49
+
50
+	/**
51
+	 * When the from or to key is inclusive
52
+	 *
53
+	 * @since 1.0.0
54
+	 */
55
+	private const INCLUSIVE = 1;
56
+
57
+	/**
58
+	 * When the from or to key is exclusive
59
+	 *
60
+	 * @since 1.0.0
61
+	 */
62
+	private const EXCLUSIVE = 2;
63
+
64
+	/**
65
+	 * @var SortedMap  Internal map
66
+	 *
67
+	 * @since 1.0.0
68
+	 */
69
+	private $map;
70
+
71
+	/**
72
+	 * @var integer  from option
73
+	 *
74
+	 * @since 1.0.0
75
+	 */
76
+	private $fromOption;
77
+
78
+	/**
79
+	 * @var mixed  from key
80
+	 *
81
+	 * @since 1.0.0
82
+	 */
83
+	private $fromKey;
84
+
85
+	/**
86
+	 * @var integer  to option
87
+	 *
88
+	 * @since 1.0.0
89
+	 */
90
+	private $toOption;
91
+
92
+	/**
93
+	 * @var mixed  to key
94
+	 *
95
+	 * @since 1.0.0
96
+	 */
97
+	private $toKey;
98
+
99
+	/**
100
+	 * @var boolean  Empty flag
101
+	 *
102
+	 * @since 1.0.0
103
+	 */
104
+	private $empty;
105
+
106
+	/**
107
+	 * Magic get method
108
+	 *
109
+	 * @param string $property The property
110
+	 *
111
+	 * @throws \RuntimeException If the property does not exist
112
+	 *
113
+	 * @return mixed The value associated to the property
114
+	 *
115
+	 * @since 1.0.0
116
+	 */
117
+	public function __get($property)
118
+	{
119
+		switch ($property) {
120
+			case 'fromKey':
121
+				if ($this->fromOption == self::UNUSED) {
122
+					 throw new \RuntimeException('Undefined property');
123
+				} else {
124
+					return $this->fromKey;
125
+				}
126
+
127
+			case 'toKey':
128
+				if ($this->toOption == self::UNUSED) {
129
+					throw new \RuntimeException('Undefined property');
130
+				} else {
131
+					return $this->toKey;
132
+				}
133
+
134
+			case 'fromInclusive':
135
+				if ($this->fromOption == self::UNUSED) {
136
+					throw new \RuntimeException('Undefined property');
137
+				} else {
138
+					return $this->fromOption == self::INCLUSIVE;
139
+				}
140
+
141
+			case 'toInclusive':
142
+				if ($this->toOption == self::UNUSED) {
143
+					throw new \RuntimeException('Undefined property');
144
+				} else {
145
+					return $this->toOption == self::INCLUSIVE;
146
+				}
147
+
148
+			case 'map':
149
+				return $this->map;
150
+			default:
151
+				return parent::__get($property);
152
+		}
153
+	}
154
+
155
+	/**
156
+	 * Magic set method
157
+	 *
158
+	 * @param string $property The property
159
+	 * @param mixed  $value    The new value
160
+	 *
161
+	 * @throws \RuntimeException If the property does not exist
162
+	 *
163
+	 * @return void
164
+	 *
165
+	 * @since 1.0.0
166
+	 */
167
+	public function __set($property, $value)
168
+	{
169
+		switch ($property) {
170
+			case 'fromKey':
171
+				$this->fromKey = $value;
172
+
173
+				if ($this->fromOption == self::UNUSED) {
174
+					 $this->fromOption = self::INCLUSIVE;
175
+				}
176
+				break;
177
+			case 'toKey':
178
+				$this->toKey = $value;
179
+
180
+				if ($this->toOption == self::UNUSED) {
181
+					$this->toOption = self::EXCLUSIVE;
182
+				}
183
+				break;
184
+			case 'fromInclusive':
185
+				if ($this->fromOption == self::UNUSED) {
186
+					throw new \RuntimeException('Undefined property');
187
+				} else {
188
+					$this->fromOption = $value ? self::INCLUSIVE : self::EXCLUSIVE;
189
+				}
190
+				break;
191
+			case 'toInclusive':
192
+				if ($this->toOption == self::UNUSED) {
193
+					throw new \RuntimeException('Undefined property');
194
+				} else {
195
+					$this->toOption = $value ? self::INCLUSIVE : self::EXCLUSIVE;
196
+				}
197
+				break;
198
+			default:
199
+				throw new \RuntimeException('Undefined property');
200
+		}
201
+
202
+		$this->setEmpty();
203
+	}
204
+
205
+	/**
206
+	 * Magic unset method
207
+	 *
208
+	 * @param string $property The property
209
+	 *
210
+	 * @throws \RuntimeException If the property does not exist
211
+	 *
212
+	 * @return void
213
+	 *
214
+	 * @since 1.0.0
215
+	 */
216
+	public function __unset($property)
217
+	{
218
+		switch ($property) {
219
+			case 'fromKey':
220
+			case 'fromInclusive':
221
+				$this->fromOption = self::UNUSED;
222
+				break;
223
+			case 'toKey':
224
+			case 'toInclusive':
225
+				$this->toOption = self::UNUSED;
226
+				break;
227
+			default:
228
+				throw new \RuntimeException('Undefined property');
229
+		}
230
+	}
231
+
232
+	/**
233
+	 * Magic isset method
234
+	 *
235
+	 * @param string $property The property
236
+	 *
237
+	 * @return boolean
238
+	 *
239
+	 * @since 1.0.0
240
+	 */
241
+	public function __isset($property)
242
+	{
243
+		switch ($property) {
244
+			case 'fromKey':
245
+			case 'fromInclusive':
246
+				return $this->fromOption != self::UNUSED;
247
+			case 'toKey':
248
+			case 'toInclusive':
249
+				return $this->toOption != self::UNUSED;
250
+			default:
251
+				return false;
252
+		}
253
+	}
254
+
255
+	/**
256
+	 * Constructor
257
+	 *
258
+	 * @param SortedMap $map        Internal map
259
+	 * @param mixed     $fromKey    The from key
260
+	 * @param integer   $fromOption The option for from (SubMap::UNUSED, SubMap::INCLUSIVE or SubMap::EXCLUSIVE)
261
+	 * @param mixed     $toKey      The to key
262
+	 * @param integer   $toOption   The option for to (SubMap::UNUSED, SubMap::INCLUSIVE or SubMap::EXCLUSIVE)
263
+	 *
264
+	 * @since 1.0.0
265
+	 */
266
+	protected function __construct(SortedMap $map, $fromKey, $fromOption, $toKey, $toOption)
267
+	{
268
+		$this->map = $map;
269
+		$this->fromKey = $fromKey;
270
+		$this->fromOption = $fromOption;
271
+		$this->toKey = $toKey;
272
+		$this->toOption = $toOption;
273
+		$this->setEmpty();
274
+	}
275
+
276
+	/**
277
+	 * Set the empty flag
278
+	 *
279
+	 * @return void
280
+	 *
281
+	 * @since 1.0.0
282
+	 */
283
+	protected function setEmpty()
284
+	{
285
+		if ($this->fromOption != self::UNUSED && $this->toOption != self::UNUSED) {
286
+			$cmp = call_user_func($this->map->comparator(), $this->fromKey, $this->toKey);
287
+
288
+			$this->empty = $cmp > 0
289
+			  || $cmp == 0 && ($this->fromOption == self::EXCLUSIVE || $this->toOption == self::EXCLUSIVE);
290
+		} else {
291
+			$this->empty = false;
292
+		}
293
+	}
294
+
295
+	/**
296
+	 * Create
297
+	 *
298
+	 * @param SortedMap $map           A sorted map
299
+	 * @param mixed     $fromKey       The from key
300
+	 * @param mixed     $toKey         The to key
301
+	 * @param boolean   $fromInclusive The inclusive flag for from
302
+	 * @param boolean   $toInclusive   The inclusive flag for to
303
+	 *
304
+	 * @return SubMap A new sub map
305
+	 *
306
+	 * @since 1.0.0
307
+	 */
308
+	public static function create(SortedMap $map, $fromKey, $toKey, $fromInclusive = true, $toInclusive = false)
309
+	{
310
+		return new static(
311
+			$map,
312
+			$fromKey,
313
+			$fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE,
314
+			$toKey,
315
+			$toInclusive ? self::INCLUSIVE : self::EXCLUSIVE
316
+		);
317
+	}
318
+
319
+	/**
320
+	 * Return a head portion of a sorted map
321
+	 *
322
+	 * @param SortedMap $map         A sorted map
323
+	 * @param mixed     $toKey       The to key
324
+	 * @param boolean   $toInclusive The inclusive flag for to
325
+	 *
326
+	 * @return SubMap A new head map
327
+	 *
328
+	 * @since 1.0.0
329
+	 */
330
+	public static function head(SortedMap $map, $toKey, $toInclusive = false)
331
+	{
332
+		return new static($map, null, self::UNUSED, $toKey, $toInclusive ? self::INCLUSIVE : self::EXCLUSIVE);
333
+	}
334
+
335
+	/**
336
+	 * Return a tail portion of a sorted map
337
+	 *
338
+	 * @param SortedMap $map           A sorted map
339
+	 * @param mixed     $fromKey       The from key
340
+	 * @param boolean   $fromInclusive The inclusive flag for from
341
+	 *
342
+	 * @return SubMap A new tail map
343
+	 *
344
+	 * @since 1.0.0
345
+	 */
346
+	public static function tail(SortedMap $map, $fromKey, $fromInclusive = true)
347
+	{
348
+		return new static($map, $fromKey, $fromInclusive ? self::INCLUSIVE : self::EXCLUSIVE, null, self::UNUSED);
349
+	}
350
+
351
+	/**
352
+	 * Return a view of the map
353
+	 *
354
+	 * @param SortedMap $map A sorted map
355
+	 *
356
+	 * @return SubMap A new sub map
357
+	 *
358
+	 * @since 1.0.0
359
+	 */
360
+	public static function view(SortedMap $map)
361
+	{
362
+		return new static($map, null, self::UNUSED, null, self::UNUSED);
363
+	}
364
+
365
+	/**
366
+	 * Get the comparator
367
+	 *
368
+	 * @return callable The comparator
369
+	 *
370
+	 * @since 1.0.0
371
+	 */
372
+	public function comparator()
373
+	{
374
+		return $this->map->comparator();
375
+	}
376
+
377
+	/**
378
+	 * Get the first element
379
+	 *
380
+	 * @return mixed The first element
381
+	 *
382
+	 * @throws \OutOfBoundsException If there is no element
383
+	 *
384
+	 * @since 1.0.0
385
+	 */
386
+	public function first()
387
+	{
388
+		if ($this->empty) {
389
+			throw new \OutOfBoundsException('First element unexisting');
390
+		}
391
+
392
+		switch ($this->fromOption) {
393
+			case self::INCLUSIVE:
394
+				$first = $this->map->ceiling($this->fromKey);
395
+				break;
396
+			case self::EXCLUSIVE:
397
+				$first = $this->map->higher($this->fromKey);
398
+				break;
399
+			default:
400
+				$first = $this->map->first();
401
+				break;
402
+		}
403
+
404
+		return $first;
405
+	}
406
+
407
+	/**
408
+	 * Get the last element
409
+	 *
410
+	 * @return mixed The last element
411
+	 *
412
+	 * @throws \OutOfBoundsException If there is no element
413
+	 *
414
+	 * @since 1.0.0
415
+	 */
416
+	public function last()
417
+	{
418
+		if ($this->empty) {
419
+			throw new \OutOfBoundsException('Last element unexisting');
420
+		}
421
+
422
+		switch ($this->toOption) {
423
+			case self::INCLUSIVE:
424
+				$last = $this->map->floor($this->toKey);
425
+				break;
426
+			case self::EXCLUSIVE:
427
+				$last = $this->map->lower($this->toKey);
428
+				break;
429
+			default:
430
+				$last = $this->map->last();
431
+				break;
432
+		}
433
+
434
+		return $last;
435
+	}
436
+
437
+	/**
438
+	 * Get the predecessor element
439
+	 *
440
+	 * @param TreeNode $element A tree node member of the underlying TreeMap
441
+	 *
442
+	 * @return mixed The predecessor element
443
+	 *
444
+	 * @throws \OutOfBoundsException If there is no predecessor
445
+	 *
446
+	 * @since 1.0.0
447
+	 */
448
+	public function predecessor($element)
449
+	{
450
+		$predecessor = $this->map->predecessor($element);
451
+
452
+		if ($predecessor) {
453
+			switch ($this->fromOption) {
454
+				case self::INCLUSIVE:
455
+					if (call_user_func($this->map->comparator(), $predecessor->key, $this->fromKey) < 0) {
456
+						throw new \OutOfBoundsException('Predecessor element unexisting');
457
+					}
458
+					break;
459
+				case self::EXCLUSIVE:
460
+					if (call_user_func($this->map->comparator(), $predecessor->key, $this->fromKey) <= 0) {
461
+						throw new \OutOfBoundsException('Predecessor element unexisting');
462
+					}
463
+					break;
464
+			}
465
+		}
466
+
467
+		return $predecessor;
468
+	}
469
+
470
+	/**
471
+	 * Get the successor element
472
+	 *
473
+	 * @param TreeNode $element A tree node member of the underlying TreeMap
474
+	 *
475
+	 * @return mixed The successor element
476
+	 *
477
+	 * @throws \OutOfBoundsException If there is no successor
478
+	 *
479
+	 * @since 1.0.0
480
+	 */
481
+	public function successor($element)
482
+	{
483
+		$successor = $this->map->successor($element);
484
+
485
+		if ($successor) {
486
+			switch ($this->toOption) {
487
+				case self::INCLUSIVE:
488
+					if (call_user_func($this->map->comparator(), $successor->key, $this->toKey) > 0) {
489
+						throw new \OutOfBoundsException('Successor element unexisting');
490
+					}
491
+					break;
492
+				case self::EXCLUSIVE:
493
+					if (call_user_func($this->map->comparator(), $successor->key, $this->toKey) >= 0) {
494
+						throw new \OutOfBoundsException('Successor element unexisting');
495
+					}
496
+					break;
497
+			}
498
+		}
499
+
500
+		return $successor;
501
+	}
502
+
503
+	/**
504
+	 * Returns the element whose key is the greatest key lesser than the given key
505
+	 *
506
+	 * @param mixed $key The searched key
507
+	 *
508
+	 * @return mixed The found element
509
+	 *
510
+	 * @throws \OutOfBoundsException If there is no lower element
511
+	 *
512
+	 * @since 1.0.0
513
+	 */
514
+	public function lower($key)
515
+	{
516
+		if ($this->empty) {
517
+			throw new \OutOfBoundsException('Lower element unexisting');
518
+		}
519
+
520
+		switch ($this->fromOption) {
521
+			case self::UNUSED:
522
+				$lower = $this->map->lower($key);
523
+				break;
524
+			default:
525
+				if (call_user_func($this->map->comparator(), $key, $this->fromKey) <= 0) {
526
+					throw new \OutOfBoundsException('Lower element unexisting');
527
+				} else {
528
+					$lower = $this->map->lower($key);
529
+
530
+					if (
531
+						$this->fromOption == self::EXCLUSIVE
532
+						  && call_user_func($this->map->comparator(), $lower->key, $this->fromKey) <= 0
533
+					) {
534
+						throw new \OutOfBoundsException('Lower element unexisting');
535
+					}
536
+				}
537
+				break;
538
+		}
539
+
540
+		if ($lower) {
541
+			switch ($this->toOption) {
542
+				case self::INCLUSIVE:
543
+					if (call_user_func($this->map->comparator(), $lower->key, $this->toKey) > 0) {
544
+						  $lower = $this->last();
545
+					}
546
+					break;
547
+				case self::EXCLUSIVE:
548
+					if (call_user_func($this->map->comparator(), $lower->key, $this->toKey) >= 0) {
549
+						$lower = $this->last();
550
+					}
551
+					break;
552
+			}
553
+		}
554
+
555
+		return $lower;
556
+	}
557
+
558
+	/**
559
+	 * Returns the element whose key is the greatest key lesser than or equal to the given key
560
+	 *
561
+	 * @param mixed $key The searched key
562
+	 *
563
+	 * @return mixed The found element
564
+	 *
565
+	 * @throws \OutOfBoundsException If there is no floor element
566
+	 *
567
+	 * @since 1.0.0
568
+	 */
569
+	public function floor($key)
570
+	{
571
+		if ($this->empty) {
572
+			throw new \OutOfBoundsException('Floor element unexisting');
573
+		}
574
+
575
+		switch ($this->fromOption) {
576
+			case self::INCLUSIVE:
577
+				if (call_user_func($this->map->comparator(), $key, $this->fromKey) < 0) {
578
+					throw new \OutOfBoundsException('Floor element unexisting');
579
+				} else {
580
+					$floor = $this->map->floor($key);
581
+				}
582
+				break;
583
+			case self::EXCLUSIVE:
584
+				if (call_user_func($this->map->comparator(), $key, $this->fromKey) <= 0) {
585
+					throw new \OutOfBoundsException('Floor element unexisting');
586
+				} else {
587
+					$floor = $this->map->floor($key);
588
+				}
589
+				break;
590
+			default:
591
+				$floor = $this->map->floor($key);
592
+				break;
593
+		}
594
+
595
+		if ($floor) {
596
+			switch ($this->toOption) {
597
+				case self::INCLUSIVE:
598
+					if (call_user_func($this->map->comparator(), $floor->key, $this->toKey) > 0) {
599
+						  $floor = $this->last();
600
+					}
601
+					break;
602
+				case self::EXCLUSIVE:
603
+					if (call_user_func($this->map->comparator(), $floor->key, $this->toKey) >= 0) {
604
+						$floor = $this->last();
605
+					}
606
+					break;
607
+			}
608
+		}
609
+
610
+		return $floor;
611
+	}
612
+
613
+	/**
614
+	 * Returns the element whose key is equal to the given key
615
+	 *
616
+	 * @param mixed $key The searched key
617
+	 *
618
+	 * @return mixed The found element
619
+	 *
620
+	 * @throws \OutOfBoundsException  If there is no such element
621
+	 *
622
+	 * @since 1.0.0
623
+	 */
624
+	public function find($key)
625
+	{
626
+		switch ($this->fromOption) {
627
+			case self::INCLUSIVE:
628
+				if (call_user_func($this->map->comparator(), $key, $this->fromKey) < 0) {
629
+					 throw new \OutOfBoundsException('Element unexisting');
630
+				}
631
+				break;
632
+			case self::EXCLUSIVE:
633
+				if (call_user_func($this->map->comparator(), $key, $this->fromKey) <= 0) {
634
+					throw new \OutOfBoundsException('Element unexisting');
635
+				}
636
+				break;
637
+		}
638
+
639
+		switch ($this->toOption) {
640
+			case self::INCLUSIVE:
641
+				if (call_user_func($this->map->comparator(), $key, $this->toKey) > 0) {
642
+					throw new \OutOfBoundsException('Element unexisting');
643
+				}
644
+				break;
645
+			case self::EXCLUSIVE:
646
+				if (call_user_func($this->map->comparator(), $key, $this->toKey) >= 0) {
647
+					throw new \OutOfBoundsException('Element unexisting');
648
+				}
649
+				break;
650
+		}
651
+
652
+		return $this->map->find($key);
653
+	}
654
+
655
+	/**
656
+	 * Returns the element whose key is the lowest key greater than or equal to the given key
657
+	 *
658
+	 * @param mixed $key The searched key
659
+	 *
660
+	 * @return mixed The found element
661
+	 *
662
+	 * @throws \OutOfBoundsException If there is no ceiling element
663
+	 *
664
+	 * @since 1.0.0
665
+	 */
666
+	public function ceiling($key)
667
+	{
668
+		if ($this->empty) {
669
+			throw new \OutOfBoundsException('Ceiling element unexisting');
670
+		}
671
+
672
+		switch ($this->toOption) {
673
+			case self::INCLUSIVE:
674
+				if (call_user_func($this->map->comparator(), $key, $this->toKey) > 0) {
675
+					throw new \OutOfBoundsException('Ceiling element unexisting');
676
+				} else {
677
+					$ceiling = $this->map->ceiling($key);
678
+				}
679
+				break;
680
+			case self::EXCLUSIVE:
681
+				if (call_user_func($this->map->comparator(), $key, $this->toKey) >= 0) {
682
+					throw new \OutOfBoundsException('Ceiling element unexisting');
683
+				} else {
684
+					$ceiling = $this->map->ceiling($key);
685
+				}
686
+				break;
687
+			default:
688
+				$ceiling = $this->map->ceiling($key);
689
+				break;
690
+		}
691
+
692
+		if ($ceiling) {
693
+			switch ($this->fromOption) {
694
+				case self::INCLUSIVE:
695
+					if (call_user_func($this->map->comparator(), $ceiling->key, $this->fromKey) < 0) {
696
+						  $ceiling = $this->first();
697
+					}
698
+					break;
699
+				case self::EXCLUSIVE:
700
+					if (call_user_func($this->map->comparator(), $ceiling->key, $this->fromKey) <= 0) {
701
+						$ceiling = $this->first();
702
+					}
703
+					break;
704
+			}
705
+		}
706
+
707
+		return $ceiling;
708
+	}
709
+
710
+	/**
711
+	 * Returns the element whose key is the lowest key greater than to the given key
712
+	 *
713
+	 * @param mixed $key The searched key
714
+	 *
715
+	 * @return mixed The found element
716
+	 *
717
+	 * @throws \OutOfBoundsException If there is no higher element
718
+	 *
719
+	 * @since 1.0.0
720
+	 */
721
+	public function higher($key)
722
+	{
723
+		if ($this->empty) {
724
+			throw new \OutOfBoundsException('Higher element unexisting');
725
+		}
726
+
727
+		switch ($this->toOption) {
728
+			case self::UNUSED:
729
+				$higher = $this->map->higher($key);
730
+				break;
731
+			default:
732
+				if (call_user_func($this->map->comparator(), $key, $this->toKey) >= 0) {
733
+					throw new \OutOfBoundsException('Higher element unexisting');
734
+				} else {
735
+					$higher = $this->map->higher($key);
736
+
737
+					if (
738
+						$this->toOption == self::EXCLUSIVE
739
+						  && call_user_func($this->map->comparator(), $higher->key, $this->toKey) >= 0
740
+					) {
741
+						throw new \OutOfBoundsException('Higher element unexisting');
742
+					}
743
+				}
744
+				break;
745
+		}
746
+
747
+		if ($higher) {
748
+			switch ($this->fromOption) {
749
+				case self::INCLUSIVE:
750
+					if (call_user_func($this->map->comparator(), $higher->key, $this->fromKey) < 0) {
751
+						  $higher = $this->first();
752
+					}
753
+					break;
754
+				case self::EXCLUSIVE:
755
+					if (call_user_func($this->map->comparator(), $higher->key, $this->fromKey) <= 0) {
756
+						$higher = $this->first();
757
+					}
758
+					break;
759
+			}
760
+		}
761
+
762
+		return $higher;
763
+	}
764
+
765
+	/**
766
+	 * Serialize the object
767
+	 *
768
+	 * @return array Array of values
769
+	 *
770
+	 * @since 1.0.0
771
+	 */
772
+	public function jsonSerialize()
773
+	{
774
+		if ($this->fromOption == self::UNUSED) {
775
+			if ($this->toOption == self::UNUSED) {
776
+				return array(
777
+					'ViewMap' => array(
778
+						'map' => $this->map->jsonSerialize(),
779
+					 )
780
+				);
781
+			} else {
782
+				return array(
783
+					'HeadMap' => array(
784
+						'map' => $this->map->jsonSerialize(),
785
+						'toKey' => $this->toKey,
786
+						'toInclusive' => $this->toOption == self::INCLUSIVE,
787
+					)
788
+				);
789
+			}
790
+		} else {
791
+			if ($this->toOption == self::UNUSED) {
792
+				return array(
793
+					'TailMap' => array(
794
+						'map' => $this->map->jsonSerialize(),
795
+						'fromKey' => $this->fromKey,
796
+						'fromInclusive' => $this->fromOption == self::INCLUSIVE,
797
+					)
798
+				);
799
+			} else {
800
+				return array(
801
+					'SubMap' => array(
802
+						'map' => $this->map->jsonSerialize(),
803
+						'fromKey' => $this->fromKey,
804
+						'fromInclusive' => $this->fromOption == self::INCLUSIVE,
805
+						'toKey' => $this->toKey,
806
+						'toInclusive' => $this->toOption == self::INCLUSIVE,
807
+					)
808
+				);
809
+			}
810
+		}
811
+	}
812
+
813
+	/**
814
+	 * Count the number of key/value pairs
815
+	 *
816
+	 * @return integer
817
+	 *
818
+	 * @since 1.0.0
819
+	 */
820
+	public function count()
821
+	{
822
+		$count = 0;
823
+
824
+		foreach ($this as $value) {
825
+			$count++;
826
+		}
827
+
828
+		return $count;
829
+	}
830 830
 }
Please login to merge, or discard this patch.