@@ -47,6 +47,62 @@ protected static function isDisjoint(?int $minA, ?int $maxA, ?int $minB, ?int $m
4747|| $ maxA !== null && $ minB !== null && $ maxA + $ offset < $ minB ;
4848}
4949
50+ /**
51+ * Return the range of integers smaller than (or equal to) the given value
52+ *
53+ * @param int|float $value
54+ * @param bool $orEqual
55+ * @return Type
56+ */
57+ public static function createAllSmallerThan ($ value , bool $ orEqual = false ): Type
58+ {
59+ if (is_int ($ value )) {
60+ return self ::fromInterval (null , $ value , $ orEqual ? 0 : -1 );
61+ }
62+
63+ if ($ value > PHP_INT_MAX || $ value >= PHP_INT_MAX && $ orEqual ) {
64+ return new IntegerType ();
65+ }
66+
67+ if ($ value < PHP_INT_MIN || $ value <= PHP_INT_MIN && !$ orEqual ) {
68+ return new NeverType ();
69+ }
70+
71+ if ($ orEqual ) {
72+ return self ::fromInterval (null , (int ) floor ($ value ));
73+ }
74+
75+ return self ::fromInterval (null , (int ) ceil ($ value ), -1 );
76+ }
77+
78+ /**
79+ * Return the range of integers greater than (or equal to) the given value
80+ *
81+ * @param int|float $value
82+ * @param bool $orEqual
83+ * @return Type
84+ */
85+ public static function createAllGreaterThan ($ value , bool $ orEqual = false ): Type
86+ {
87+ if (is_int ($ value )) {
88+ return self ::fromInterval ($ value , null , $ orEqual ? 0 : 1 );
89+ }
90+
91+ if ($ value < PHP_INT_MIN || $ value <= PHP_INT_MIN && $ orEqual ) {
92+ return new IntegerType ();
93+ }
94+
95+ if ($ value > PHP_INT_MAX || $ value >= PHP_INT_MAX && !$ orEqual ) {
96+ return new NeverType ();
97+ }
98+
99+ if ($ orEqual ) {
100+ return self ::fromInterval ((int ) ceil ($ value ), null );
101+ }
102+
103+ return self ::fromInterval ((int ) floor ($ value ), null , 1 );
104+ }
105+
50106public function getMin (): ?int
51107{
52108return $ this ->min ;
@@ -213,6 +269,43 @@ public function isGreaterThan(Type $otherType, bool $orEqual = false): TrinaryLo
213269return TrinaryLogic::extremeIdentity ($ minIsSmaller , $ maxIsSmaller );
214270}
215271
272+ public function getSmallerType (bool $ orEqual = false ): Type
273+ {
274+ $ subtractedTypes = [];
275+
276+ if ($ this ->max !== null ) {
277+ $ subtractedTypes [] = self ::createAllGreaterThan ($ this ->max , !$ orEqual );
278+ }
279+
280+ if (!$ orEqual ) {
281+ $ subtractedTypes [] = new ConstantBooleanType (true );
282+ }
283+
284+ return TypeCombinator::remove (new MixedType (), TypeCombinator::union (...$ subtractedTypes ));
285+ }
286+
287+ public function getGreaterType (bool $ orEqual = false ): Type
288+ {
289+ $ subtractedTypes = [];
290+
291+ if ($ this ->min !== null ) {
292+ $ subtractedTypes [] = self ::createAllSmallerThan ($ this ->min , !$ orEqual );
293+ }
294+
295+ $ alwaysTruthy = $ this ->min !== null && $ this ->min > 0 || $ this ->max !== null && $ this ->max < 0 ;
296+
297+ if ($ alwaysTruthy || !$ orEqual ) {
298+ $ subtractedTypes [] = new NullType ();
299+ $ subtractedTypes [] = new ConstantBooleanType (false );
300+ }
301+
302+ if ($ alwaysTruthy && !$ orEqual ) {
303+ $ subtractedTypes [] = new ConstantBooleanType (true );
304+ }
305+
306+ return TypeCombinator::remove (new MixedType (), TypeCombinator::union (...$ subtractedTypes ));
307+ }
308+
216309public function toNumber (): Type
217310{
218311return new parent ();
0 commit comments