1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.jexl3;
19
20 import java.math.BigInteger;
21 import java.math.MathContext;
22
23 /**
24 * An arithmetic that tries to keep argument types for bit-twiddling operators.
25 */
26 public class Arithmetic360 extends JexlArithmetic {
27 public Arithmetic360(final boolean astrict) {
28 super(astrict);
29 }
30
31 public Arithmetic360(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
32 super(astrict, bigdContext, bigdScale);
33 }
34
35 /**
36 * Performs a bitwise and.
37 *
38 * @param left the left operand
39 * @param right the right operator
40 * @return left & right
41 */
42 @Override
43 public Object and(final Object left, final Object right) {
44 final Number l = asLongNumber(left);
45 final Number r = asLongNumber(right);
46 if (l != null && r != null) {
47 return narrowLong(left, right, l.longValue() & r.longValue());
48 }
49 return toBigInteger(left).and(toBigInteger(right));
50 }
51
52 /**
53 * Checks if value class is a number that can be represented exactly in a long.
54 *
55 * @param value argument
56 * @return true if argument can be represented by a long
57 */
58 protected Number asIntNumber(final Object value) {
59 return value instanceof Integer
60 || value instanceof Short
61 || value instanceof Byte
62 ? (Number) value
63 : null;
64 }
65 /**
66 * Casts to Long if possible.
67 * @param value the Long or else
68 * @return the Long or null
69 */
70 protected Long castLongNumber(final Object value) {
71 return value instanceof Long ? (Long) value : null;
72 }
73
74 /**
75 * Performs a bitwise complement.
76 *
77 * @param val the operand
78 * @return ~val
79 */
80 @Override
81 public Object complement(final Object val) {
82 final long l = toLong(val);
83 return narrowLong(val, ~l);
84 }
85
86 /**
87 * Given a long, attempt to narrow it to an int.
88 * <p>Narrowing will only occur if the initial operand is not a Long.
89 * @param operand the operand that lead to the long result
90 * @param result the long result to narrow
91 * @return an Integer if narrowing is possible, the original Long otherwise
92 */
93 protected Number narrowLong(final Object operand, final long result) {
94 if (!(operand instanceof Long)) {
95 final int ir = (int) result;
96 if (result == ir) {
97 return ir;
98 }
99 }
100 return result;
101 }
102
103 /**
104 * Given a long, attempt to narrow it to an int.
105 * <p>Narrowing will only occur if no operand is a Long.
106 * @param lhs the left-hand side operand that lead to the long result
107 * @param rhs the right-hand side operand that lead to the long result
108 * @param result the long to narrow
109 * @return an Integer if narrowing is possible, the original Long otherwise
110 */
111 @Override
112 protected Number narrowLong(final Object lhs, final Object rhs, final long result) {
113 if (!(lhs instanceof Long || rhs instanceof Long)) {
114 final int ir = (int) result;
115 if (result == ir) {
116 return ir;
117 }
118 }
119 return result;
120 }
121
122 /**
123 * Performs a bitwise or.
124 *
125 * @param left the left operand
126 * @param right the right operator
127 * @return left | right
128 */
129 @Override
130 public Object or(final Object left, final Object right) {
131 final Number l = asLongNumber(left);
132 final Number r = asLongNumber(right);
133 if (l != null && r != null) {
134 return narrowLong(left, right, l.longValue() | r.longValue());
135 }
136 return toBigInteger(left).or(toBigInteger(right));
137 }
138
139 /**
140 * Shifts a bit pattern to the right.
141 *
142 * @param left left argument
143 * @param right right argument
144 * @return left << right.
145 */
146 @Override
147 public Object shiftLeft(final Object left, final Object right) {
148 if (left == null && right == null) {
149 return controlNullNullOperands(JexlOperator.SHIFTLEFT);
150 }
151 final int r = toInteger(right);
152 Number l = asIntNumber(left);
153 if (l != null) {
154 return l.intValue() << r;
155 }
156 l = castLongNumber(left);
157 if (l != null) {
158 return l.longValue() << r;
159 }
160 return toBigInteger(left).shiftLeft(r);
161 }
162
163 /**
164 * Shifts a bit pattern to the right.
165 *
166 * @param left left argument
167 * @param right right argument
168 * @return left >> right.
169 */
170 @Override
171 public Object shiftRight(final Object left, final Object right) {
172 if (left == null && right == null) {
173 return controlNullNullOperands(JexlOperator.SHIFTRIGHT);
174 }
175 final int r = toInteger(right);
176 Number l = asIntNumber(left);
177 if (l != null) {
178 return l.intValue() >> r;
179 }
180 l = castLongNumber(left);
181 if (l != null) {
182 return l.longValue() >> r;
183 }
184 return toBigInteger(left).shiftRight(r);
185 }
186
187 /**
188 * Shifts a bit pattern to the right unsigned.
189 *
190 * @param left left argument
191 * @param right right argument
192 * @return left >>> right.
193 */
194 @Override
195 public Object shiftRightUnsigned(final Object left, final Object right) {
196 if (left == null && right == null) {
197 return controlNullNullOperands(JexlOperator.SHIFTRIGHTU);
198 }
199 final int r = toInteger(right);
200 Number l = asIntNumber(left);
201 if (l != null) {
202 return l.intValue() >>> r;
203 }
204 l = castLongNumber(left);
205 if (l != null) {
206 return l.longValue() >>> r;
207 }
208 final BigInteger bl = toBigInteger(left);
209 return bl.signum() < 0? bl.negate().shiftRight(r) : bl.shiftRight(r);
210 }
211
212 /**
213 * Performs a bitwise xor.
214 *
215 * @param left the left operand
216 * @param right the right operator
217 * @return left ^ right
218 */
219 @Override
220 public Object xor(final Object left, final Object right) {
221 final Number l = asLongNumber(left);
222 final Number r = asLongNumber(right);
223 if (l != null && r != null) {
224 return narrowLong(left, right, l.longValue() ^ r.longValue());
225 }
226 return toBigInteger(left).xor(toBigInteger(right));
227 }
228
229 }