/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.addthis.hydra.data.query.op;
import com.addthis.bundle.core.Bundle;
import com.addthis.hydra.data.filter.util.BundleCalculator;
import com.addthis.hydra.data.query.AbstractRowOp;
import io.netty.channel.ChannelProgressivePromise;
/**
* <p>This query operation <span class="hydra-summary">performs postfix (RPN) calculator
* numeric operations</span>.
* <p/>
* <p>This filter uses a calculation stack to perform arithmetic operations. The stack is initially empty
* and values can be pushed or popped from the top of the stack. Arithmetic operations can be performed
* on the element(s) at the top of the stack.
* <pre style="font-family:courier;font-size:15px">
* num=OP,OP,OP,...
* <p/>
* OP := LOAD_OP | CALC_OP
* LOAD_OP := LOAD_COL | LOAD_NUM | LOAD_VAL
* LOAD_COL := ("c" | "col" ) INT ( ":" INT )*
* LOAD_NUM := ("n" | "num") FLOAT ( ":" FLOAT)*
* LOAD_VAL := ("v" | "val") FLOAT
* CALC_OP := [see table for operations]
* INT := DIGIT+
* FLOAT := DIGIT* ("." DIGIT*)?
* DIGIT := ["0" - "9"]</pre>
* <p/>
* <p>The following operations below are available. Each operation proceeds in three steps:
* (1) Zero or more values are popped off the stack, (2) an operation is performed on these values,
* and (3) zero or more values are pushed onto the stack. For convenience the following table
* labels the first element popped off the stack as "a" (the topmost element), the second
* element as "b", etc. The variables "X","Y","Z", etc. represent numbers in the command sequence.
* <p/>
* <table width="80%" class="num">
* <tr>
* <th width="15%">name</th>
* <th width="10%">pop count</th>
* <th width="65%">operation</th>
* <th width="10%">push count</th>
* </tr>
* <tr>
* <td>"+" or "add"</td>
* <td>2</td>
* <td>add a and b</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"-" or "sub"</td>
* <td>2</td>
* <td>subtract a from b</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"*" or "mult" or "prod"</td>
* <td>2</td>
* <td>long integer multiplication</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"dmult" or "dprod"</td>
* <td>2</td>
* <td>floating point multiplication</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"/" or "div"</td>
* <td>2</td>
* <td>long integer divide the b by a.
* <br>If diverr is false and a is 0 then return 0.</br></td>
* <td>1</td>
* </tr>
* <tr>
* <td>"ddiv"</td>
* <td>2</td>
* <td>floating point divide the b by a.
* <br>If diverr is false and a is 0.0 then return 0.</br></td>
* <td>1</td>
* </tr>
* <tr>
* <td>"log"</td>
* <td>1</td>
* <td>compute logarithm base 10 of a</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"%" or "rem"</td>
* <td>2</td>
* <td>modulo b by a
* <br>If diverr is false and a is 0 then return 0.</br></td>
* <td>1</td>
* </tr>
* <tr>
* <td>"=" or "s" or "set"</td>
* <td>2</td>
* <td>assign the a-th column the value of b.
* <br>If a is out of bounds then
* append b to the end of the bundle</br></td>
* <td>0</td>
* </tr>
* <tr>
* <td>"pop" or "drop"</td>
* <td>1</td>
* <td>pop the top element off the stack</td>
* <td>0</td>
* </tr>
* <tr>
* <td>"x" or "swap"</td>
* <td>2</td>
* <td>swap the positions of a and b</td>
* <td>2</td>
* </tr>
* <tr>
* <td>"d" or "dup"</td>
* <td>1</td>
* <td>duplicate element a</td>
* <td>2</td>
* </tr>
* <tr>
* <td>">" or "gt"</td>
* <td>2</td>
* <td>if long integer (b > a) is false then end the calculation</td>
* <td>0</td>
* </tr>
* <tr>
* <td>">=" or "gteq"</td>
* <td>2</td>
* <td>if long integer (b >= a) is false then end the calculation</td>
* <td>0</td>
* </tr>
* <tr>
* <td>"<" or "lt"</td>
* <td>2</td>
* <td>if long integer (b < a) is false then end the calculation</td>
* <td>0</td>
* </tr>
* <tr>
* <td>"<=" or "lteq"</td>
* <td>2</td>
* <td>if long integer (b <= a) is false then end the calculation</td>
* <td>0</td>
* </tr>
* <tr>
* <td>"toi" or "toint"</td>
* <td>1</td>
* <td>convert a to a long integer</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"tof" or "tofloat"</td>
* <td>1</td>
* <td>convert a to a floating-point value</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"tob" or "tobits"</td>
* <td>1</td>
* <td>convert floating point a to its bitwise long representation</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"btof" or "btofloat"</td>
* <td>1</td>
* <td>convert the bitwise representation of long a to a floating-point value</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"out" or "shiftout"</td>
* <td>1</td>
* <td>append a to the end of the bundle</td>
* <td>0</td>
* </tr>
* <tr>
* <td>"sqrt"</td>
* <td>1</td>
* <td>calculate the square root of a</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"diverr"</td>
* <td>0</td>
* <td>set the diverr flag to true</td>
* <td>0</td>
* </tr>
* <tr>
* <td>">>" or "dgt"</td>
* <td>2</td>
* <td>if floating-point (b > a) is false then end the calculation</td>
* <td>0</td>
* </tr>
* <tr>
* <td>">>=" or "dgteq"</td>
* <td>2</td>
* <td>if floating-point (b >= a) is false then end the calculation</td>
* <td>0</td>
* </tr>
* <tr>
* <td>"<<" or "dlt"</td>
* <td>2</td>
* <td>if floating-point (b < a) is false then end the calculation</td>
* <td>0</td>
* </tr>
* <tr>
* <td>"<<=" or "dlteq"</td>
* <td>2</td>
* <td>if floating-point (b <= a) is false then end the calculation</td>
* <td>0</td>
* </tr>
* <tr>
* <td>"==" or "deq"</td>
* <td>2</td>
* <td>if floating-point (b == a) is false then end the calculation</td>
* <td>0</td>
* </tr>
* <tr>
* <td>"min"</td>
* <td>2</td>
* <td>return a copy of the minimum of a and b</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"max"</td>
* <td>2</td>
* <td>return a copy of the maximum of a and b</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"minif"</td>
* <td>2</td>
* <td>return the minimum of a and b</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"maxif"</td>
* <td>2</td>
* <td>return the maximum of a and b</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"abs"</td>
* <td>1</td>
* <td>return the absolute value of a as a float</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"mean"</td>
* <td>ALL</td>
* <td>consumes all values on the stack and returns the mean</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"variance"</td>
* <td>ALL</td>
* <td>consumes all values on the stack and returns the (population) variance</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"aX:Y:Z..."</td>
* <td>0</td>
* <td>push the arrays in columns X, Y, Z,... onto the stack</td>
* <td>array length</td>
* </tr>
* <tr>
* <td>"cX:Y:Z..."</td>
* <td>0</td>
* <td>push the value in columns X, Y, Z,... onto the stack</td>
* <td>len(args)</td>
* </tr>
* <tr>
* <td>"nX:Y:Z..."</td>
* <td>0</td>
* <td>push the values X, Y, Z,... onto the stack</td>
* <td>len(args)</td>
* </tr>
* <tr>
* <td>"vX"</td>
* <td>0</td>
* <td>push the value X onto the stack</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"hX"</td>
* <td>0</td>
* <td>evaluate the current hash function on the column X, and push the resulting number onto the stack</td>
* <td>1</td>
* </tr>
* <tr>
* <td>"vector"</td>
* <td>0</td>
* <td>modifies the behavior of the next operation.<br>
* Next operation pops all elements off the stack<br>
* and pushes a single value onto the stack. Available<br>
* for "+", "mult", "dmult", "min", and "max".
* <td>0</td>
* </tr>
* </table>
* <p/>
* <p/>
* <p>Example:</p>
* <p/>
* <pre>
* A 1 art
* B 2 bot
* C 3 cog
* D 4 din
*
* num=n5,c1,rem,v2,set
*
* A 1 0
* B 2 1
* C 3 2
* D 4 1
* </pre>
*
* @user-reference
* @hydra-name num or math
*/
public class OpNumber extends AbstractRowOp {
private BundleCalculator calculator;
/**
* Note: this now delegates to BundleCalculator.
*/
public OpNumber(String args, ChannelProgressivePromise queryPromise) {
super(queryPromise);
calculator = new BundleCalculator(args);
}
@Override
public Bundle rowOp(Bundle line) {
return calculator.calculate(line);
}
}