View Javadoc
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      /**
67       * Casts to Long if possible.
68       * @param value the Long or else
69       * @return the Long or null
70       */
71      protected Long castLongNumber(final Object value) {
72          return value instanceof Long ? (Long) value : null;
73      }
74  
75      /**
76       * Performs a bitwise complement.
77       *
78       * @param val the operand
79       * @return ~val
80       */
81      @Override
82      public Object complement(final Object val) {
83          final long l = toLong(val);
84          return narrowLong(val, ~l);
85      }
86  
87      /**
88       * Given a long, attempt to narrow it to an int.
89       * <p>Narrowing will only occur if the initial operand is not a Long.
90       * @param operand  the operand that lead to the long result
91       * @param result the long result to narrow
92       * @return an Integer if narrowing is possible, the original Long otherwise
93       */
94      protected Number narrowLong(final Object operand, final long result) {
95          if (!(operand instanceof Long)) {
96              final int ir = (int) result;
97              if (result == ir) {
98                  return ir;
99              }
100         }
101         return result;
102     }
103 
104     /**
105      * Given a long, attempt to narrow it to an int.
106      * <p>Narrowing will only occur if no operand is a Long.
107      * @param lhs  the left-hand side operand that lead to the long result
108      * @param rhs  the right-hand side operand that lead to the long result
109      * @param result the long to narrow
110      * @return an Integer if narrowing is possible, the original Long otherwise
111      */
112     @Override
113     protected Number narrowLong(final Object lhs, final Object rhs, final long result) {
114         if (!(lhs instanceof Long || rhs instanceof Long)) {
115             final int ir = (int) result;
116             if (result == ir) {
117                 return ir;
118             }
119         }
120         return result;
121     }
122 
123     /**
124      * Performs a bitwise or.
125      *
126      * @param left  the left operand
127      * @param right the right operator
128      * @return left | right
129      */
130     @Override
131     public Object or(final Object left, final Object right) {
132         final Number l = asLongNumber(left);
133         final Number r = asLongNumber(right);
134         if (l != null && r != null) {
135             return narrowLong(left, right, l.longValue() | r.longValue());
136         }
137         return toBigInteger(left).or(toBigInteger(right));
138     }
139 
140     /**
141      * Shifts a bit pattern to the right.
142      *
143      * @param left  left argument
144      * @param right  right argument
145      * @return left &lt;&lt; right.
146      */
147     @Override
148     public Object shiftLeft(final Object left, final Object right) {
149         if (left == null && right == null) {
150             return controlNullNullOperands(JexlOperator.SHIFTLEFT);
151         }
152         final int r = toInteger(right);
153         Number l = asIntNumber(left);
154         if (l != null) {
155             return l.intValue() << r;
156         }
157         l = castLongNumber(left);
158         if (l != null) {
159             return l.longValue() << r;
160         }
161         return toBigInteger(left).shiftLeft(r);
162     }
163 
164     /**
165      * Shifts a bit pattern to the right.
166      *
167      * @param left  left argument
168      * @param right  right argument
169      * @return left &gt;&gt; right.
170      */
171     @Override
172     public Object shiftRight(final Object left, final Object right) {
173         if (left == null && right == null) {
174             return controlNullNullOperands(JexlOperator.SHIFTRIGHT);
175         }
176         final int r = toInteger(right);
177         Number l = asIntNumber(left);
178         if (l != null) {
179             return l.intValue() >> r;
180         }
181         l = castLongNumber(left);
182         if (l != null) {
183             return l.longValue() >> r;
184         }
185         return toBigInteger(left).shiftRight(r);
186     }
187 
188     /**
189      * Shifts a bit pattern to the right unsigned.
190      *
191      * @param left  left argument
192      * @param right  right argument
193      * @return left &gt;&gt;&gt; right.
194      */
195     @Override
196     public Object shiftRightUnsigned(final Object left, final Object right) {
197         if (left == null && right == null) {
198             return controlNullNullOperands(JexlOperator.SHIFTRIGHTU);
199         }
200         final int r = toInteger(right);
201         Number l = asIntNumber(left);
202         if (l != null) {
203             return l.intValue() >>> r;
204         }
205         l = castLongNumber(left);
206         if (l != null) {
207             return l.longValue() >>> r;
208         }
209         final BigInteger bl = toBigInteger(left);
210         return bl.signum() < 0? bl.negate().shiftRight(r) : bl.shiftRight(r);
211     }
212 
213     /**
214      * Performs a bitwise xor.
215      *
216      * @param left  the left operand
217      * @param right the right operator
218      * @return left ^ right
219      */
220     @Override
221     public Object xor(final Object left, final Object right) {
222         final Number l = asLongNumber(left);
223         final Number r = asLongNumber(right);
224         if (l != null && r != null) {
225             return narrowLong(left, right, l.longValue() ^ r.longValue());
226         }
227         return toBigInteger(left).xor(toBigInteger(right));
228     }
229 
230 }