1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jexl3;
19
20 import static java.lang.StrictMath.floor;
21 import static org.apache.commons.jexl3.JexlOperator.EQ;
22
23 import java.lang.reflect.Array;
24 import java.lang.reflect.Constructor;
25 import java.lang.reflect.InvocationTargetException;
26 import java.lang.reflect.Method;
27 import java.math.BigDecimal;
28 import java.math.BigInteger;
29 import java.math.MathContext;
30 import java.util.Collection;
31 import java.util.Map;
32 import java.util.concurrent.atomic.AtomicBoolean;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
35
36 import org.apache.commons.jexl3.introspection.JexlMethod;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class JexlArithmetic {
62
63
64
65
66
67
68
69
70
71
72
73
74 public interface ArrayBuilder {
75
76
77
78
79
80
81 void add(Object value);
82
83
84
85
86
87
88
89 Object create(boolean extended);
90 }
91
92
93 public static class CoercionException extends ArithmeticException {
94 private static final long serialVersionUID = 202402081150L;
95
96
97
98
99
100
101 public CoercionException(final String msg) {
102 super(msg);
103 }
104
105
106
107
108
109
110
111
112 public CoercionException(final String msg, final Throwable cause) {
113 super(msg);
114 initCause(cause);
115 }
116 }
117
118
119
120
121
122 public interface MapBuilder {
123
124
125
126
127
128 Object create();
129
130
131
132
133
134
135
136 void put(Object key, Object value);
137 }
138
139
140 public static class NullOperand extends ArithmeticException {
141 private static final long serialVersionUID = 4720876194840764770L;
142
143
144 public NullOperand() {
145 }
146 }
147
148
149
150
151
152 public interface SetBuilder {
153
154
155
156
157
158 void add(Object value);
159
160
161
162
163
164
165 Object create();
166 }
167
168
169
170
171
172 public interface Uberspect {
173
174
175
176
177
178
179
180 JexlMethod getOperator(JexlOperator operator, Object... args);
181
182
183
184
185
186
187
188 boolean overloads(JexlOperator operator);
189 }
190
191
192 protected static final BigDecimal BIGD_DOUBLE_MAX_VALUE = BigDecimal.valueOf(Double.MAX_VALUE);
193
194
195 protected static final BigDecimal BIGD_DOUBLE_MIN_VALUE = BigDecimal.valueOf(-Double.MAX_VALUE);
196
197
198 protected static final BigInteger BIGI_LONG_MAX_VALUE = BigInteger.valueOf(Long.MAX_VALUE);
199
200
201 protected static final BigInteger BIGI_LONG_MIN_VALUE = BigInteger.valueOf(Long.MIN_VALUE);
202
203
204 protected static final int BIGD_SCALE = -1;
205
206
207
208
209
210
211
212 public static final Pattern FLOAT_PATTERN = Pattern.compile("^[+-]?\\d*(\\.\\d*)?([eE][+-]?\\d+)?$");
213
214
215
216
217
218
219
220
221 private static Object arrayWrap(final Object container) {
222 return container.getClass().isArray()
223 ? new org.apache.commons.jexl3.internal.introspection.ArrayListWrapper(container)
224 : container;
225 }
226
227 private static boolean computeCompare321(final JexlArithmetic arithmetic) {
228 Class<?> arithmeticClass = arithmetic.getClass();
229 while(arithmeticClass != JexlArithmetic.class) {
230 try {
231 final Method cmp = arithmeticClass.getDeclaredMethod("compare", Object.class, Object.class, String.class);
232 if (cmp.getDeclaringClass() != JexlArithmetic.class) {
233 return true;
234 }
235 } catch (final NoSuchMethodException xany) {
236 arithmeticClass = arithmeticClass.getSuperclass();
237 }
238 }
239 return false;
240 }
241
242
243
244
245
246
247
248
249
250 @SuppressWarnings("MagicNumber")
251 protected static boolean isMultiplyExact(final long x, final long y, final long r) {
252 final long ax = Math.abs(x);
253 final long ay = Math.abs(y);
254
255
256
257 return !((ax | ay) >>> Integer.SIZE - 1 != 0
258 && (y != 0 && r / y != x
259 || x == Long.MIN_VALUE && y == -1));
260 }
261
262
263 private final boolean strict;
264
265
266 private final MathContext mathContext;
267
268
269 private final int mathScale;
270
271
272 private final Constructor<? extends JexlArithmetic> ctor;
273
274
275
276
277
278 private final boolean compare321 = computeCompare321(this);
279
280
281
282
283
284
285
286
287 public JexlArithmetic(final boolean astrict) {
288 this(astrict, null, Integer.MIN_VALUE);
289 }
290
291
292
293
294
295
296
297
298
299 public JexlArithmetic(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
300 this.strict = astrict;
301 this.mathContext = bigdContext == null ? MathContext.DECIMAL128 : bigdContext;
302 this.mathScale = bigdScale == Integer.MIN_VALUE ? BIGD_SCALE : bigdScale;
303 Constructor<? extends JexlArithmetic> actor = null;
304 try {
305 actor = getClass().getConstructor(boolean.class, MathContext.class, int.class);
306 } catch (final Exception xany) {
307
308 }
309 this.ctor = actor;
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323 public Object add(final Object left, final Object right) {
324 if (left == null && right == null) {
325 return controlNullNullOperands(JexlOperator.ADD);
326 }
327 final boolean strconcat = strict
328 ? left instanceof String || right instanceof String
329 : left instanceof String && right instanceof String;
330 if (!strconcat) {
331 try {
332 final boolean strictCast = isStrict(JexlOperator.ADD);
333
334 final Number ln = asLongNumber(strictCast, left);
335 final Number rn = asLongNumber(strictCast, right);
336 if (ln != null && rn != null) {
337 final long x = ln.longValue();
338 final long y = rn.longValue();
339 final long result = x + y;
340
341 if (((x ^ result) & (y ^ result)) < 0) {
342 return BigInteger.valueOf(x).add(BigInteger.valueOf(y));
343 }
344 return narrowLong(left, right, result);
345 }
346
347 if (left instanceof BigDecimal || right instanceof BigDecimal) {
348 final BigDecimal l = toBigDecimal(strictCast, left);
349 final BigDecimal r = toBigDecimal(strictCast, right);
350 return l.add(r, getMathContext());
351 }
352
353 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
354 final double l = toDouble(strictCast, left);
355 final double r = toDouble(strictCast, right);
356 return l + r;
357 }
358
359 final BigInteger l = toBigInteger(strictCast, left);
360 final BigInteger r = toBigInteger(strictCast, right);
361 final BigInteger result = l.add(r);
362 return narrowBigInteger(left, right, result);
363 } catch (final ArithmeticException nfe) {
364
365 }
366 }
367 return (left == null ? "" : toString(left)).concat(right == null ? "" : toString(right));
368 }
369
370
371
372
373
374
375
376
377 public Object and(final Object left, final Object right) {
378 final long l = toLong(left);
379 final long r = toLong(right);
380 return l & r;
381 }
382
383
384
385
386
387
388
389 @Deprecated
390 public ArrayBuilder arrayBuilder(final int size) {
391 return arrayBuilder(size, false);
392 }
393
394
395
396
397
398
399
400
401 public ArrayBuilder arrayBuilder(final int size, final boolean extended) {
402 return new org.apache.commons.jexl3.internal.ArrayBuilder(size, extended);
403 }
404
405
406
407
408
409
410
411
412
413 protected Number asLongNumber(final boolean strict, final Object value) {
414 if (value instanceof Long
415 || value instanceof Integer
416 || value instanceof Short
417 || value instanceof Byte) {
418 return (Number) value;
419 }
420 if (value instanceof Boolean) {
421 return (boolean) value ? 1L : 0L;
422 }
423 if (value instanceof AtomicBoolean) {
424 final AtomicBoolean b = (AtomicBoolean) value;
425 return b.get() ? 1L : 0L;
426 }
427 if (value == null && !strict) {
428 return 0L;
429 }
430 return null;
431 }
432
433
434
435
436
437
438
439
440 protected Number asLongNumber(final Object value) {
441 return asLongNumber(strict, value);
442 }
443
444
445
446
447
448
449
450
451
452 @Deprecated
453 public final Object bitwiseAnd(final Object lhs, final Object rhs) {
454 return and(lhs, rhs);
455 }
456
457
458
459
460
461
462
463
464
465
466 @Deprecated
467 public final Object bitwiseOr(final Object lhs, final Object rhs) {
468 return or(lhs, rhs);
469 }
470
471
472
473
474
475
476
477
478
479
480 @Deprecated
481 public final Object bitwiseXor(final Object lhs, final Object rhs) {
482 return xor(lhs, rhs);
483 }
484
485
486
487
488
489
490
491
492 protected Boolean collectionContains(final Object collection, final Object value) {
493
494 final Object left = arrayWrap(collection);
495 if (left instanceof Collection) {
496 final Object right = arrayWrap(value);
497 if (right instanceof Collection) {
498 return ((Collection<?>) left).containsAll((Collection<?>) right);
499 }
500 return ((Collection<?>) left).contains(value);
501 }
502 return null;
503 }
504
505
506
507
508
509
510
511
512
513
514 protected int compare(final Object left, final Object right, final JexlOperator operator) {
515
516
517 return compare321
518 ? compare(left, right, operator.toString())
519 : doCompare(left, right, operator);
520 }
521
522
523
524
525
526
527
528
529
530
531 @Deprecated
532 protected int compare(final Object left, final Object right, final String symbol) {
533 JexlOperator operator;
534 try {
535 operator = JexlOperator.valueOf(symbol);
536 } catch (final IllegalArgumentException xill) {
537
538 operator = EQ;
539 }
540 return doCompare(left, right, operator);
541 }
542
543
544
545
546
547
548
549 public Object complement(final Object val) {
550 final boolean strictCast = isStrict(JexlOperator.COMPLEMENT);
551 final long l = toLong(strictCast, val);
552 return ~l;
553 }
554
555
556
557
558
559
560
561
562
563
564
565
566 public Boolean contains(final Object container, final Object value) {
567 if (value == null && container == null) {
568
569 return true;
570 }
571 if (value == null || container == null) {
572
573 return false;
574 }
575
576 if (container instanceof java.util.regex.Pattern) {
577 return ((java.util.regex.Pattern) container).matcher(value.toString()).matches();
578 }
579 if (container instanceof CharSequence) {
580 return value.toString().matches(container.toString());
581 }
582
583 if (container instanceof Map<?, ?>) {
584 if (value instanceof Map<?, ?>) {
585 return ((Map<?, ?>) container).keySet().containsAll(((Map<?, ?>) value).keySet());
586 }
587 return ((Map<?, ?>) container).containsKey(value);
588 }
589
590 return collectionContains(container, value);
591 }
592
593
594
595
596
597
598
599
600 @Deprecated
601 protected Object controlNullNullOperands() {
602 if (isStrict()) {
603 throw new NullOperand();
604 }
605 return 0;
606 }
607
608
609
610
611
612
613
614
615 protected Object controlNullNullOperands(final JexlOperator operator) {
616 if (isStrict(operator)) {
617 throw new NullOperand();
618 }
619 return 0;
620 }
621
622
623
624
625
626
627
628 @Deprecated
629 protected void controlNullOperand() {
630 if (isStrict()) {
631 throw new NullOperand();
632 }
633 }
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649 protected <T> T controlNullOperand(final boolean strictCast, final T defaultValue) {
650 if (strictCast) {
651 throw new NullOperand();
652 }
653 return defaultValue;
654 }
655
656
657
658
659
660
661 public Object controlReturn(final Object returned) {
662 return returned;
663 }
664
665
666
667
668
669
670
671
672
673
674 public Iterable<?> createRange(final Object from, final Object to) throws ArithmeticException {
675 final long lfrom = toLong(from);
676 final long lto = toLong(to);
677 if (lfrom >= Integer.MIN_VALUE && lfrom <= Integer.MAX_VALUE
678 && lto >= Integer.MIN_VALUE && lto <= Integer.MAX_VALUE) {
679 return org.apache.commons.jexl3.internal.IntegerRange.create((int) lfrom, (int) lto);
680 }
681 return org.apache.commons.jexl3.internal.LongRange.create(lfrom, lto);
682 }
683
684
685
686
687
688
689
690
691
692
693
694 protected JexlArithmetic createWithOptions(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
695 if (ctor != null) {
696 try {
697 return ctor.newInstance(astrict, bigdContext, bigdScale);
698 } catch (IllegalAccessException | IllegalArgumentException
699 | InstantiationException | InvocationTargetException xany) {
700
701 }
702 }
703 return new JexlArithmetic(astrict, bigdContext, bigdScale);
704 }
705
706
707
708
709
710
711 public Object decrement(final Object val) {
712 return increment(val, -1);
713 }
714
715
716
717
718
719
720
721
722
723 public Object divide(final Object left, final Object right) {
724 if (left == null && right == null) {
725 return controlNullNullOperands(JexlOperator.DIVIDE);
726 }
727 final boolean strictCast = isStrict(JexlOperator.DIVIDE);
728
729 final Number ln = asLongNumber(strictCast, left);
730 final Number rn = asLongNumber(strictCast, right);
731 if (ln != null && rn != null) {
732 final long x = ln.longValue();
733 final long y = rn.longValue();
734 if (y == 0L) {
735 throw new ArithmeticException("/");
736 }
737 final long result = x / y;
738 return narrowLong(left, right, result);
739 }
740
741 if (left instanceof BigDecimal || right instanceof BigDecimal) {
742 final BigDecimal l = toBigDecimal(strictCast, left);
743 final BigDecimal r = toBigDecimal(strictCast, right);
744 if (BigDecimal.ZERO.equals(r)) {
745 throw new ArithmeticException("/");
746 }
747 return l.divide(r, getMathContext());
748 }
749
750 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
751 final double l = toDouble(strictCast, left);
752 final double r = toDouble(strictCast, right);
753 if (r == 0.0) {
754 throw new ArithmeticException("/");
755 }
756 return l / r;
757 }
758
759 final BigInteger l = toBigInteger(strictCast, left);
760 final BigInteger r = toBigInteger(strictCast, right);
761 if (BigInteger.ZERO.equals(r)) {
762 throw new ArithmeticException("/");
763 }
764 final BigInteger result = l.divide(r);
765 return narrowBigInteger(left, right, result);
766 }
767
768 private int doCompare(final Object left, final Object right, final JexlOperator operator) {
769 final boolean strictCast = isStrict(operator);
770 if (left != null && right != null) {
771 try {
772 if (left instanceof BigDecimal || right instanceof BigDecimal) {
773 final BigDecimal l = toBigDecimal(strictCast, left);
774 final BigDecimal r = toBigDecimal(strictCast, right);
775 return l.compareTo(r);
776 }
777 if (left instanceof BigInteger || right instanceof BigInteger) {
778 final BigInteger l = toBigInteger(strictCast, left);
779 final BigInteger r = toBigInteger(strictCast, right);
780 return l.compareTo(r);
781 }
782 if (isFloatingPoint(left) || isFloatingPoint(right)) {
783 final double lhs = toDouble(strictCast, left);
784 final double rhs = toDouble(strictCast, right);
785 if (Double.isNaN(lhs)) {
786 if (Double.isNaN(rhs)) {
787 return 0;
788 }
789 return -1;
790 }
791 if (Double.isNaN(rhs)) {
792
793 return +1;
794 }
795 return Double.compare(lhs, rhs);
796 }
797 if (isNumberable(left) || isNumberable(right)) {
798 final long lhs = toLong(strictCast, left);
799 final long rhs = toLong(strictCast, right);
800 return Long.compare(lhs, rhs);
801 }
802 if (left instanceof String || right instanceof String) {
803 return toString(left).compareTo(toString(right));
804 }
805 } catch (final CoercionException ignore) {
806
807 }
808 if (EQ == operator) {
809 return left.equals(right) ? 0 : -1;
810 }
811 if (left instanceof Comparable<?>) {
812 @SuppressWarnings("unchecked")
813 final Comparable<Object> comparable = (Comparable<Object>) left;
814 try {
815 return comparable.compareTo(right);
816 } catch (final ClassCastException castException) {
817
818 }
819 }
820 if (right instanceof Comparable<?>) {
821 @SuppressWarnings("unchecked")
822 final Comparable<Object> comparable = (Comparable<Object>) right;
823 try {
824 return -Integer.signum(comparable.compareTo(left));
825 } catch (final ClassCastException castException) {
826
827 }
828 }
829 }
830 throw new ArithmeticException("Object comparison:(" + left +
831 " " + operator.getOperatorSymbol()
832 + " " + right + ")");
833 }
834
835
836
837
838
839
840
841
842 public Boolean empty(final Object object) {
843 return object == null || isEmpty(object, false);
844 }
845
846
847
848
849
850
851
852
853 public Boolean endsWith(final Object left, final Object right) {
854 if (left == null && right == null) {
855
856 return true;
857 }
858 if (left == null || right == null) {
859
860 return false;
861 }
862 if (left instanceof CharSequence) {
863 return toString(left).endsWith(toString(right));
864 }
865 return null;
866 }
867
868
869
870
871
872
873
874
875 public boolean equals(final Object left, final Object right) {
876 if (left == right) {
877 return true;
878 }
879 if (left == null || right == null) {
880 return false;
881 }
882 final boolean strictCast = isStrict(EQ);
883 if (left instanceof Boolean || right instanceof Boolean) {
884 return toBoolean(left) == toBoolean(strictCast, right);
885 }
886 return compare(left, right, EQ) == 0;
887 }
888
889
890
891
892
893
894 public MathContext getMathContext() {
895 return mathContext;
896 }
897
898
899
900
901
902
903 public int getMathScale() {
904 return mathScale;
905 }
906
907
908
909
910
911
912
913
914 public boolean greaterThan(final Object left, final Object right) {
915 if (left == right || left == null || right == null) {
916 return false;
917 }
918 return compare(left, right, JexlOperator.GT) > 0;
919 }
920
921
922
923
924
925
926
927
928 public boolean greaterThanOrEqual(final Object left, final Object right) {
929 if (left == right) {
930 return true;
931 }
932 if (left == null || right == null) {
933 return false;
934 }
935 return compare(left, right, JexlOperator.GTE) >= 0;
936 }
937
938
939
940
941
942
943 public Object increment(final Object val) {
944 return increment(val, 1);
945 }
946
947
948
949
950
951
952
953 protected Object increment(final Object val, final int incr) {
954 if (val == null) {
955 return incr;
956 }
957 if (val instanceof Integer) {
958 return (Integer) val + incr;
959 }
960 if (val instanceof Double) {
961 return (Double) val + incr;
962 }
963 if (val instanceof Long) {
964 return (Long) val + incr;
965 }
966 if (val instanceof BigDecimal) {
967 final BigDecimal bd = (BigDecimal) val;
968 return bd.add(BigDecimal.valueOf(incr), this.mathContext);
969 }
970 if (val instanceof BigInteger) {
971 final BigInteger bi = (BigInteger) val;
972 return bi.add(BigInteger.valueOf(incr));
973 }
974 if (val instanceof Float) {
975 return (Float) val + incr;
976 }
977 if (val instanceof Short) {
978 return (short) ((Short) val + incr);
979 }
980 if (val instanceof Byte) {
981 return (byte) ((Byte) val + incr);
982 }
983 throw new ArithmeticException("Object "+(incr < 0? "decrement":"increment")+":(" + val + ")");
984 }
985
986
987
988
989
990
991
992 public Boolean isEmpty(final Object object) {
993 return isEmpty(object, object == null);
994 }
995
996
997
998
999
1000
1001
1002
1003 public Boolean isEmpty(final Object object, final Boolean def) {
1004 if (object != null) {
1005 if (object instanceof Number) {
1006 final double d = ((Number) object).doubleValue();
1007 return Double.isNaN(d) || d == 0.d;
1008 }
1009 if (object instanceof CharSequence) {
1010 return ((CharSequence) object).length() == 0;
1011 }
1012 if (object.getClass().isArray()) {
1013 return Array.getLength(object) == 0;
1014 }
1015 if (object instanceof Collection<?>) {
1016 return ((Collection<?>) object).isEmpty();
1017 }
1018
1019 if (object instanceof Map<?, ?>) {
1020 return ((Map<?, ?>) object).isEmpty();
1021 }
1022 }
1023 return def;
1024 }
1025
1026
1027
1028
1029
1030
1031
1032 protected boolean isFloatingPoint(final Object o) {
1033 return o instanceof Float || o instanceof Double;
1034 }
1035
1036
1037
1038
1039
1040
1041
1042
1043 protected boolean isFloatingPointNumber(final Object val) {
1044 if (val instanceof Float || val instanceof Double) {
1045 return true;
1046 }
1047 if (val instanceof CharSequence) {
1048 final Matcher m = FLOAT_PATTERN.matcher((CharSequence) val);
1049
1050
1051 return m.matches() && (m.start(1) >= 0 || m.start(2) >= 0);
1052 }
1053 return false;
1054 }
1055
1056
1057
1058
1059
1060
1061
1062
1063 public boolean isNegateStable() {
1064 return true;
1065 }
1066
1067
1068
1069
1070
1071
1072 protected boolean isNullOperand(final Object value) {
1073 return value == null;
1074 }
1075
1076
1077
1078
1079
1080
1081
1082 protected boolean isNumberable(final Object o) {
1083 return o instanceof Integer
1084 || o instanceof Long
1085 || o instanceof Byte
1086 || o instanceof Short
1087 || o instanceof Character;
1088 }
1089
1090
1091
1092
1093
1094
1095
1096
1097 public boolean isPositivizeStable() {
1098 return true;
1099 }
1100
1101
1102
1103
1104
1105
1106
1107 public boolean isStrict() {
1108 return strict;
1109 }
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124 public boolean isStrict(final JexlOperator operator) {
1125 if (operator != null) {
1126 switch (operator) {
1127 case EQ:
1128 case EQSTRICT:
1129 case ARRAY_GET:
1130 case ARRAY_SET:
1131 case PROPERTY_GET:
1132 case PROPERTY_SET:
1133 case EMPTY:
1134 case SIZE:
1135 case CONTAINS:
1136 return false;
1137 default:
1138 return isStrict();
1139 }
1140 }
1141 return isStrict();
1142 }
1143
1144
1145
1146
1147
1148
1149
1150
1151 public boolean lessThan(final Object left, final Object right) {
1152 if (left == right || left == null || right == null) {
1153 return false;
1154 }
1155 return compare(left, right, JexlOperator.LT) < 0;
1156
1157 }
1158
1159
1160
1161
1162
1163
1164
1165
1166 public boolean lessThanOrEqual(final Object left, final Object right) {
1167 if (left == right) {
1168 return true;
1169 }
1170 if (left == null || right == null) {
1171 return false;
1172 }
1173 return compare(left, right, JexlOperator.LTE) <= 0;
1174 }
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184 @Deprecated
1185 public final Object logicalNot(final Object arg) {
1186 return not(arg);
1187 }
1188
1189
1190
1191
1192
1193
1194
1195 @Deprecated
1196 public MapBuilder mapBuilder(final int size) {
1197 return mapBuilder(size, false);
1198 }
1199
1200
1201
1202
1203
1204
1205
1206
1207 public MapBuilder mapBuilder(final int size, final boolean extended) {
1208 return new org.apache.commons.jexl3.internal.MapBuilder(size, extended);
1209 }
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220 @Deprecated
1221 public final Object matches(final Object lhs, final Object rhs) {
1222 return contains(rhs, lhs);
1223 }
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233 public Object mod(final Object left, final Object right) {
1234 if (left == null && right == null) {
1235 return controlNullNullOperands(JexlOperator.MOD);
1236 }
1237 final boolean strictCast = isStrict(JexlOperator.MOD);
1238
1239 final Number ln = asLongNumber(strictCast, left);
1240 final Number rn = asLongNumber(strictCast, right);
1241 if (ln != null && rn != null) {
1242 final long x = ln.longValue();
1243 final long y = rn.longValue();
1244 if (y == 0L) {
1245 throw new ArithmeticException("%");
1246 }
1247 final long result = x % y;
1248 return narrowLong(left, right, result);
1249 }
1250
1251 if (left instanceof BigDecimal || right instanceof BigDecimal) {
1252 final BigDecimal l = toBigDecimal(strictCast, left);
1253 final BigDecimal r = toBigDecimal(strictCast, right);
1254 if (BigDecimal.ZERO.equals(r)) {
1255 throw new ArithmeticException("%");
1256 }
1257 return l.remainder(r, getMathContext());
1258 }
1259
1260 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1261 final double l = toDouble(strictCast, left);
1262 final double r = toDouble(strictCast, right);
1263 if (r == 0.0) {
1264 throw new ArithmeticException("%");
1265 }
1266 return l % r;
1267 }
1268
1269 final BigInteger l = toBigInteger(strictCast, left);
1270 final BigInteger r = toBigInteger(strictCast, right);
1271 if (BigInteger.ZERO.equals(r)) {
1272 throw new ArithmeticException("%");
1273 }
1274 final BigInteger result = l.mod(r);
1275 return narrowBigInteger(left, right, result);
1276 }
1277
1278
1279
1280
1281
1282
1283
1284
1285 public Object multiply(final Object left, final Object right) {
1286 if (left == null && right == null) {
1287 return controlNullNullOperands(JexlOperator.MULTIPLY);
1288 }
1289 final boolean strictCast = isStrict(JexlOperator.MULTIPLY);
1290
1291 final Number ln = asLongNumber(strictCast, left);
1292 final Number rn = asLongNumber(strictCast, right);
1293 if (ln != null && rn != null) {
1294 final long x = ln.longValue();
1295 final long y = rn.longValue();
1296 final long result = x * y;
1297
1298 if (!isMultiplyExact(x, y, result)) {
1299 return BigInteger.valueOf(x).multiply(BigInteger.valueOf(y));
1300 }
1301 return narrowLong(left, right, result);
1302 }
1303
1304 if (left instanceof BigDecimal || right instanceof BigDecimal) {
1305 final BigDecimal l = toBigDecimal(strictCast, left);
1306 final BigDecimal r = toBigDecimal(strictCast, right);
1307 return l.multiply(r, getMathContext());
1308 }
1309
1310 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1311 final double l = toDouble(strictCast, left);
1312 final double r = toDouble(strictCast, right);
1313 return l * r;
1314 }
1315
1316 final BigInteger l = toBigInteger(strictCast, left);
1317 final BigInteger r = toBigInteger(strictCast, right);
1318 final BigInteger result = l.multiply(r);
1319 return narrowBigInteger(left, right, result);
1320 }
1321
1322
1323
1324
1325
1326
1327
1328 private Number narrow(final Class<?> narrow, final double value) {
1329 return narrowAccept(narrow, Float.class) && (float) value == value
1330 ? (float) value
1331 : value;
1332 }
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345 public Number narrow(final Number original) {
1346 return narrowNumber(original, null);
1347 }
1348
1349
1350
1351
1352
1353
1354
1355
1356 protected boolean narrowAccept(final Class<?> narrow, final Class<?> source) {
1357 return narrow == null || narrow.equals(source);
1358 }
1359
1360
1361
1362
1363
1364
1365
1366
1367 public boolean narrowArguments(final Object[] args) {
1368 boolean narrowed = false;
1369 if (args != null) {
1370 for (int a = 0; a < args.length; ++a) {
1371 final Object arg = args[a];
1372 if (arg instanceof Number) {
1373 final Number narg = (Number) arg;
1374 final Number narrow = narrow(narg);
1375 if (!narg.equals(narrow)) {
1376 args[a] = narrow;
1377 narrowed = true;
1378 }
1379 }
1380 }
1381 }
1382 return narrowed;
1383 }
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394 protected Number narrowBigDecimal(final Object lhs, final Object rhs, final BigDecimal big) {
1395 if (isNumberable(lhs) || isNumberable(rhs)) {
1396 try {
1397 final long l = big.longValueExact();
1398
1399 if ((int) l == l) {
1400 return (int) l;
1401 }
1402 return l;
1403 } catch (final ArithmeticException xa) {
1404
1405 }
1406 }
1407 return big;
1408 }
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424 protected Number narrowBigInteger(final Object lhs, final Object rhs, final BigInteger big) {
1425 if (isNumberable(lhs) || isNumberable(rhs)) {
1426 try {
1427 final long l = big.longValueExact();
1428
1429 if ((int) l == l) {
1430 return (int) l;
1431 }
1432 return l;
1433 } catch (final ArithmeticException xa) {
1434
1435 }
1436 }
1437 return big;
1438 }
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448 protected Number narrowLong(final Object lhs, final Object rhs, final long r) {
1449 if (!(lhs instanceof Long || rhs instanceof Long) && (int) r == r) {
1450 return (int) r;
1451 }
1452 return r;
1453 }
1454
1455
1456
1457
1458
1459
1460
1461
1462 public Number narrowNumber(final Number original, final Class<?> narrow) {
1463 if (original != null) {
1464 final long value;
1465 if (original instanceof BigDecimal) {
1466 final BigDecimal big = (BigDecimal) original;
1467 try {
1468
1469 value = big.longValueExact();
1470
1471 } catch (final ArithmeticException xa) {
1472
1473 if (big.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0
1474 || big.compareTo(BIGD_DOUBLE_MIN_VALUE) < 0) {
1475 return original;
1476 }
1477
1478 return narrow(narrow, original.doubleValue());
1479 }
1480
1481 } else {
1482 if (isFloatingPoint(original)) {
1483 final double doubleValue = original.doubleValue();
1484
1485 if ((long) doubleValue != doubleValue) {
1486 return narrow(narrow, doubleValue);
1487 }
1488
1489 } else if (original instanceof BigInteger) {
1490 final BigInteger bigi = (BigInteger) original;
1491
1492 if (!BigInteger.valueOf(bigi.longValue()).equals(bigi)) {
1493 return original;
1494 }
1495
1496 }
1497 value = original.longValue();
1498 }
1499
1500 if (narrowAccept(narrow, Byte.class) && (byte) value == value) {
1501
1502 return (byte) value;
1503 }
1504 if (narrowAccept(narrow, Short.class) && (short) value == value) {
1505 return (short) value;
1506 }
1507 if (narrowAccept(narrow, Integer.class) && (int) value == value) {
1508 return (int) value;
1509 }
1510 }
1511 return original;
1512 }
1513
1514
1515
1516
1517
1518
1519
1520
1521 public Object negate(final Object val) {
1522 if (val == null) {
1523 return null;
1524 }
1525 if (val instanceof Integer) {
1526 return -((Integer) val);
1527 }
1528 if (val instanceof Double) {
1529 return - ((Double) val);
1530 }
1531 if (val instanceof Long) {
1532 return -((Long) val);
1533 }
1534 if (val instanceof BigDecimal) {
1535 return ((BigDecimal) val).negate();
1536 }
1537 if (val instanceof BigInteger) {
1538 return ((BigInteger) val).negate();
1539 }
1540 if (val instanceof Float) {
1541 return -((Float) val);
1542 }
1543 if (val instanceof Short) {
1544 return (short) -((Short) val);
1545 }
1546 if (val instanceof Byte) {
1547 return (byte) -((Byte) val);
1548 }
1549 if (val instanceof Boolean) {
1550 return !(Boolean) val;
1551 }
1552 if (val instanceof AtomicBoolean) {
1553 return !((AtomicBoolean) val).get();
1554 }
1555 throw new ArithmeticException("Object negate:(" + val + ")");
1556 }
1557
1558
1559
1560
1561
1562
1563
1564 public Object not(final Object val) {
1565 final boolean strictCast = isStrict(JexlOperator.NOT);
1566 return !toBoolean(strictCast, val);
1567 }
1568
1569
1570
1571
1572
1573
1574
1575
1576 public JexlArithmetic options(final JexlContext context) {
1577 if (context instanceof JexlContext.OptionsHandle) {
1578 return options(((JexlContext.OptionsHandle) context).getEngineOptions());
1579 }
1580 if (context instanceof JexlEngine.Options) {
1581 return options((JexlEngine.Options) context);
1582 }
1583 return this;
1584 }
1585
1586
1587
1588
1589
1590
1591
1592
1593 @Deprecated
1594 public JexlArithmetic options(final JexlEngine.Options options) {
1595 if (options != null) {
1596 final boolean isstrict = Boolean.TRUE == options.isStrictArithmetic() || isStrict();
1597 MathContext bigdContext = options.getArithmeticMathContext();
1598 if (bigdContext == null) {
1599 bigdContext = getMathContext();
1600 }
1601 int bigdScale = options.getArithmeticMathScale();
1602 if (bigdScale == Integer.MIN_VALUE) {
1603 bigdScale = getMathScale();
1604 }
1605 if (isstrict != isStrict()
1606 || bigdScale != getMathScale()
1607 || bigdContext != getMathContext()) {
1608 return createWithOptions(isstrict, bigdContext, bigdScale);
1609 }
1610 }
1611 return this;
1612 }
1613
1614
1615
1616
1617
1618
1619
1620 public JexlArithmetic options(final JexlOptions options) {
1621 if (options != null) {
1622 final boolean ostrict = options.isStrictArithmetic();
1623 MathContext bigdContext = options.getMathContext();
1624 if (bigdContext == null) {
1625 bigdContext = getMathContext();
1626 }
1627 int bigdScale = options.getMathScale();
1628 if (bigdScale == Integer.MIN_VALUE) {
1629 bigdScale = getMathScale();
1630 }
1631 if (ostrict != isStrict()
1632 || bigdScale != getMathScale()
1633 || bigdContext != getMathContext()) {
1634 return createWithOptions(ostrict, bigdContext, bigdScale);
1635 }
1636 }
1637 return this;
1638 }
1639
1640
1641
1642
1643
1644
1645
1646
1647 public Object or(final Object left, final Object right) {
1648 final long l = toLong(left);
1649 final long r = toLong(right);
1650 return l | r;
1651 }
1652
1653
1654
1655
1656
1657
1658
1659
1660 private BigDecimal parseBigDecimal(final String arg) throws ArithmeticException {
1661 try {
1662 return arg.isEmpty()? BigDecimal.ZERO : new BigDecimal(arg, getMathContext());
1663 } catch (final NumberFormatException e) {
1664 throw new CoercionException("BigDecimal coercion: ("+ arg +")", e);
1665 }
1666 }
1667
1668
1669
1670
1671
1672
1673
1674
1675 private BigInteger parseBigInteger(final String arg) throws ArithmeticException {
1676 try {
1677 return arg.isEmpty()? BigInteger.ZERO : new BigInteger(arg);
1678 } catch (final NumberFormatException e) {
1679 throw new CoercionException("BigDecimal coercion: ("+ arg +")", e);
1680 }
1681 }
1682
1683
1684
1685
1686
1687
1688
1689
1690 private double parseDouble(final String arg) throws ArithmeticException {
1691 try {
1692 return arg.isEmpty()? Double.NaN : Double.parseDouble(arg);
1693 } catch (final NumberFormatException e) {
1694 throw new CoercionException("Double coercion: ("+ arg +")", e);
1695 }
1696 }
1697
1698
1699
1700
1701
1702
1703
1704
1705 private int parseInteger(final String arg) throws ArithmeticException {
1706 final long l = parseLong(arg);
1707 final int i = (int) l;
1708 if (i == l) {
1709 return i;
1710 }
1711 throw new CoercionException("Int coercion: ("+ arg +")");
1712 }
1713
1714
1715
1716
1717
1718
1719
1720
1721 private long parseLong(final String arg) throws ArithmeticException {
1722 final double d = parseDouble(arg);
1723 if (Double.isNaN(d)) {
1724 return 0L;
1725 }
1726 final double f = floor(d);
1727 if (d == f) {
1728 return (long) d;
1729 }
1730 throw new CoercionException("Long coercion: ("+ arg +")");
1731 }
1732
1733
1734
1735
1736
1737
1738
1739 public static Integer parseIdentifier(final Object id) {
1740 if (id instanceof Number) {
1741 return ((Number) id).intValue();
1742 }
1743
1744 if (id instanceof CharSequence) {
1745 final CharSequence str = (CharSequence) id;
1746 final int length = str.length();
1747
1748 if (length > 0 && length <= 10) {
1749 int val = 0;
1750 for (int i = 0; i < length; ++i) {
1751 final char c = str.charAt(i);
1752
1753 if (c == '0' && val == 0 && length > 1 || c < '0' || c > '9') {
1754 return null;
1755 }
1756 val *= 10;
1757 val += c - '0';
1758 }
1759 return val;
1760 }
1761 }
1762 return null;
1763 }
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773 public Object positivize(final Object val) {
1774 if (val == null) {
1775 return null;
1776 }
1777 if (val instanceof Short) {
1778 return ((Short) val).intValue();
1779 }
1780 if (val instanceof Byte) {
1781 return ((Byte) val).intValue();
1782 }
1783 if (val instanceof Number) {
1784 return val;
1785 }
1786 if (val instanceof Character) {
1787 return (int) (Character) val;
1788 }
1789 if (val instanceof Boolean) {
1790 return val;
1791 }
1792 if (val instanceof AtomicBoolean) {
1793 return ((AtomicBoolean) val).get();
1794 }
1795 throw new ArithmeticException("Object positivize:(" + val + ")");
1796 }
1797
1798
1799
1800
1801
1802
1803
1804 protected BigDecimal roundBigDecimal(final BigDecimal number) {
1805 final int mscale = getMathScale();
1806 if (mscale >= 0) {
1807 return number.setScale(mscale, getMathContext().getRoundingMode());
1808 }
1809 return number;
1810 }
1811
1812
1813
1814
1815
1816
1817
1818 @Deprecated
1819 public SetBuilder setBuilder(final int size) {
1820 return setBuilder(size, false);
1821 }
1822
1823
1824
1825
1826
1827
1828
1829
1830 public SetBuilder setBuilder(final int size, final boolean extended) {
1831 return new org.apache.commons.jexl3.internal.SetBuilder(size, extended);
1832 }
1833
1834
1835
1836
1837
1838
1839
1840
1841 public Object shiftLeft(final Object left, final Object right) {
1842 final long l = toLong(left);
1843 final int r = toInteger(right);
1844 return l << r;
1845 }
1846
1847
1848
1849
1850
1851
1852
1853
1854 public Object shiftRight(final Object left, final Object right) {
1855 final long l = toLong(left);
1856 final long r = toInteger(right);
1857 return l >> r;
1858 }
1859
1860
1861
1862
1863
1864
1865
1866
1867 public Object shiftRightUnsigned(final Object left, final Object right) {
1868 final long l = toLong(left);
1869 final long r = toInteger(right);
1870 return l >>> r;
1871 }
1872
1873
1874
1875
1876
1877
1878
1879 public Integer size(final Object object) {
1880 return size(object, object == null ? 0 : 1);
1881 }
1882
1883
1884
1885
1886
1887
1888
1889
1890 public Integer size(final Object object, final Integer def) {
1891 if (object instanceof CharSequence) {
1892 return ((CharSequence) object).length();
1893 }
1894 if (object.getClass().isArray()) {
1895 return Array.getLength(object);
1896 }
1897 if (object instanceof Collection<?>) {
1898 return ((Collection<?>) object).size();
1899 }
1900 if (object instanceof Map<?, ?>) {
1901 return ((Map<?, ?>) object).size();
1902 }
1903 return def;
1904 }
1905
1906
1907
1908
1909
1910
1911
1912 public Boolean startsWith(final Object left, final Object right) {
1913 if (left == null && right == null) {
1914
1915 return true;
1916 }
1917 if (left == null || right == null) {
1918
1919 return false;
1920 }
1921 if (left instanceof CharSequence) {
1922 return toString(left).startsWith(toString(right));
1923 }
1924 return null;
1925 }
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935 public boolean strictEquals(final Object left, final Object right) {
1936 if (left == right) {
1937 return true;
1938 }
1939 if (left == null || right == null) {
1940 return false;
1941 }
1942 if (left.getClass().equals(right.getClass())) {
1943 return left.equals(right);
1944 }
1945 return false;
1946 }
1947
1948
1949
1950
1951
1952
1953
1954
1955 public Object subtract(final Object left, final Object right) {
1956 if (left == null && right == null) {
1957 return controlNullNullOperands(JexlOperator.SUBTRACT);
1958 }
1959 final boolean strictCast = isStrict(JexlOperator.SUBTRACT);
1960
1961 final Number ln = asLongNumber(strictCast, left);
1962 final Number rn = asLongNumber(strictCast, right);
1963 if (ln != null && rn != null) {
1964 final long x = ln.longValue();
1965 final long y = rn.longValue();
1966 final long result = x - y;
1967
1968 if (((x ^ y) & (x ^ result)) < 0) {
1969 return BigInteger.valueOf(x).subtract(BigInteger.valueOf(y));
1970 }
1971 return narrowLong(left, right, result);
1972 }
1973
1974 if (left instanceof BigDecimal || right instanceof BigDecimal) {
1975 final BigDecimal l = toBigDecimal(strictCast, left);
1976 final BigDecimal r = toBigDecimal(strictCast, right);
1977 return l.subtract(r, getMathContext());
1978 }
1979
1980 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1981 final double l = toDouble(strictCast, left);
1982 final double r = toDouble(strictCast, right);
1983 return l - r;
1984 }
1985
1986 final BigInteger l = toBigInteger(strictCast, left);
1987 final BigInteger r = toBigInteger(strictCast, right);
1988 final BigInteger result = l.subtract(r);
1989 return narrowBigInteger(left, right, result);
1990 }
1991
1992
1993
1994
1995
1996
1997
1998 public boolean testPredicate(final Object object) {
1999 final boolean strictCast = isStrict(JexlOperator.CONDITION);
2000 return toBoolean(strictCast, object);
2001 }
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014 protected BigDecimal toBigDecimal(final boolean strict, final Object val) {
2015 return isNullOperand(val)? controlNullOperand(strict, BigDecimal.ZERO) : toBigDecimal(val);
2016 }
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027 public BigDecimal toBigDecimal(final Object val) {
2028 if (val instanceof BigDecimal) {
2029 return roundBigDecimal((BigDecimal) val);
2030 }
2031 if (val instanceof Double) {
2032 if (Double.isNaN((Double) val)) {
2033 return BigDecimal.ZERO;
2034 }
2035 return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
2036 }
2037 if (val instanceof Number) {
2038 return roundBigDecimal(parseBigDecimal(val.toString()));
2039 }
2040 if (val instanceof Boolean) {
2041 return BigDecimal.valueOf((boolean) val ? 1. : 0.);
2042 }
2043 if (val instanceof AtomicBoolean) {
2044 return BigDecimal.valueOf(((AtomicBoolean) val).get() ? 1L : 0L);
2045 }
2046 if (val instanceof String) {
2047 return roundBigDecimal(parseBigDecimal((String) val));
2048 }
2049 if (val instanceof Character) {
2050 return new BigDecimal((Character) val);
2051 }
2052 if (val == null) {
2053 return controlNullOperand(strict, BigDecimal.ZERO);
2054 }
2055 throw new CoercionException("BigDecimal coercion: "
2056 + val.getClass().getName() + ":(" + val + ")");
2057 }
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070 protected BigInteger toBigInteger(final boolean strict, final Object val) {
2071 return isNullOperand(val)? controlNullOperand(strict, BigInteger.ZERO) : toBigInteger(val);
2072 }
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083 public BigInteger toBigInteger(final Object val) {
2084 if (val instanceof BigInteger) {
2085 return (BigInteger) val;
2086 }
2087 if (val instanceof Double) {
2088 final Double dval = (Double) val;
2089 if (Double.isNaN(dval)) {
2090 return BigInteger.ZERO;
2091 }
2092 return BigInteger.valueOf(dval.longValue());
2093 }
2094 if (val instanceof BigDecimal) {
2095 return ((BigDecimal) val).toBigInteger();
2096 }
2097 if (val instanceof Number) {
2098 return BigInteger.valueOf(((Number) val).longValue());
2099 }
2100 if (val instanceof Boolean) {
2101 return BigInteger.valueOf((boolean) val ? 1L : 0L);
2102 }
2103 if (val instanceof AtomicBoolean) {
2104 return BigInteger.valueOf(((AtomicBoolean) val).get() ? 1L : 0L);
2105 }
2106 if (val instanceof String) {
2107 return parseBigInteger((String) val);
2108 }
2109 if (val instanceof Character) {
2110 final int i = (Character) val;
2111 return BigInteger.valueOf(i);
2112 }
2113 if (val == null) {
2114 return controlNullOperand(strict, BigInteger.ZERO);
2115 }
2116 throw new CoercionException("BigInteger coercion: "
2117 + val.getClass().getName() + ":(" + val + ")");
2118 }
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128 protected boolean toBoolean(final boolean strict, final Object val) {
2129 return isNullOperand(val)? controlNullOperand(strict, false) : toBoolean(val);
2130 }
2131
2132
2133
2134
2135
2136
2137
2138
2139 public boolean toBoolean(final Object val) {
2140 if (val instanceof Boolean) {
2141 return (Boolean) val;
2142 }
2143 if (val instanceof Number) {
2144 final double number = toDouble(strict, val);
2145 return !Double.isNaN(number) && number != 0.d;
2146 }
2147 if (val instanceof AtomicBoolean) {
2148 return ((AtomicBoolean) val).get();
2149 }
2150 if (val instanceof String) {
2151 final String strval = val.toString();
2152 return !strval.isEmpty() && !"false".equals(strval);
2153 }
2154 if (val == null) {
2155 return controlNullOperand(strict, false);
2156 }
2157
2158 return true;
2159 }
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172 protected double toDouble(final boolean strict, final Object val) {
2173 return isNullOperand(val)? controlNullOperand(strict, 0.d) : toDouble(val);
2174 }
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185 public double toDouble(final Object val) {
2186 if (val instanceof Double) {
2187 return (Double) val;
2188 }
2189 if (val instanceof Number) {
2190 return ((Number) val).doubleValue();
2191 }
2192 if (val instanceof Boolean) {
2193 return (boolean) val ? 1. : 0.;
2194 }
2195 if (val instanceof AtomicBoolean) {
2196 return ((AtomicBoolean) val).get() ? 1. : 0.;
2197 }
2198 if (val instanceof String) {
2199 return parseDouble((String) val);
2200 }
2201 if (val instanceof Character) {
2202 return (Character) val;
2203 }
2204 if (val == null) {
2205 return controlNullOperand(strict, 0.d);
2206 }
2207 throw new CoercionException("Double coercion: "
2208 + val.getClass().getName() + ":(" + val + ")");
2209 }
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222 protected int toInteger(final boolean strict, final Object val) {
2223 return isNullOperand(val)? controlNullOperand(strict, 0) : toInteger(val);
2224 }
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235 public int toInteger(final Object val) {
2236 if (val instanceof Double) {
2237 final double dval = (Double) val;
2238 return Double.isNaN(dval)? 0 : (int) dval;
2239 }
2240 if (val instanceof Number) {
2241 return ((Number) val).intValue();
2242 }
2243 if (val instanceof String) {
2244 return parseInteger((String) val);
2245 }
2246 if (val instanceof Boolean) {
2247 return (boolean) val ? 1 : 0;
2248 }
2249 if (val instanceof AtomicBoolean) {
2250 return ((AtomicBoolean) val).get() ? 1 : 0;
2251 }
2252 if (val instanceof Character) {
2253 return (Character) val;
2254 }
2255 if (val == null) {
2256 return controlNullOperand(strict, 0);
2257 }
2258 throw new CoercionException("Integer coercion: "
2259 + val.getClass().getName() + ":(" + val + ")");
2260 }
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273 protected long toLong(final boolean strict, final Object val) {
2274 return isNullOperand(val)? controlNullOperand(strict, 0L) : toLong(val);
2275 }
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286 public long toLong(final Object val) {
2287 if (val instanceof Double) {
2288 final double dval = (Double) val;
2289 return Double.isNaN(dval)? 0L : (long) dval;
2290 }
2291 if (val instanceof Number) {
2292 return ((Number) val).longValue();
2293 }
2294 if (val instanceof String) {
2295 return parseLong((String) val);
2296 }
2297 if (val instanceof Boolean) {
2298 return (boolean) val ? 1L : 0L;
2299 }
2300 if (val instanceof AtomicBoolean) {
2301 return ((AtomicBoolean) val).get() ? 1L : 0L;
2302 }
2303 if (val instanceof Character) {
2304 return (Character) val;
2305 }
2306 if (val == null) {
2307 return controlNullOperand(strict, 0L);
2308 }
2309 throw new CoercionException("Long coercion: "
2310 + val.getClass().getName() + ":(" + val + ")");
2311 }
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323 protected String toString(final boolean strict, final Object val) {
2324 return isNullOperand(val)? controlNullOperand(strict, "") : toString(val);
2325 }
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335 public String toString(final Object val) {
2336 if (val instanceof Double) {
2337 final Double dval = (Double) val;
2338 if (Double.isNaN(dval)) {
2339 return "";
2340 }
2341 return dval.toString();
2342 }
2343 return val == null ? controlNullOperand(strict, "") : val.toString();
2344 }
2345
2346
2347
2348
2349
2350
2351
2352
2353 public Object xor(final Object left, final Object right) {
2354 final long l = toLong(left);
2355 final long r = toLong(right);
2356 return l ^ r;
2357 }
2358 }