aboutsummaryrefslogtreecommitdiffstats
path: root/document/src/main/java/com/yahoo/document/update/ArithmeticValueUpdate.java
blob: 155b4368aedb5639513c9b9844ed9038185958dc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.document.update;

import com.yahoo.document.DataType;
import com.yahoo.document.NumericDataType;
import com.yahoo.document.datatypes.DoubleFieldValue;
import com.yahoo.document.datatypes.FieldValue;
import com.yahoo.document.datatypes.NumericFieldValue;
import com.yahoo.document.serialization.DocumentUpdateWriter;

/**
 * <p>Value update representing an arithmetic operation on a numeric data type.</p>
 *
 * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a>
 */
public class ArithmeticValueUpdate extends ValueUpdate<DoubleFieldValue> {
    protected Operator operator;
    protected DoubleFieldValue operand;

    public ArithmeticValueUpdate(Operator operator, DoubleFieldValue operand) {
        super(ValueUpdateClassID.ARITHMETIC);
        this.operator = operator;
        this.operand = operand;
    }

    public ArithmeticValueUpdate(Operator operator, Number operand) {
        this(operator, new DoubleFieldValue(operand.doubleValue()));
    }

    /**
     * Returns the operator of this arithmatic value update.
     *
     * @return the operator
     * @see com.yahoo.document.update.ArithmeticValueUpdate.Operator
     */
    public Operator getOperator() {
        return operator;
    }

    /**
     * Returns the operand of this arithmetic value update.
     *
     * @return the operand
     */
    public Number getOperand() {
        return operand.getDouble();
    }

    /** Returns the operand */
    public DoubleFieldValue getValue() { return operand; }

    /** Sets the operand */
    public void setValue(DoubleFieldValue value) { operand=value; }

    @Override
    public FieldValue applyTo(FieldValue oldValue) {
        if (oldValue instanceof NumericFieldValue) {
            Number number = (Number) oldValue.getWrappedValue();
            oldValue.assign(calculate(number));
        } else {
            throw new IllegalStateException("Cannot use arithmetic value update on non-numeric datatype "+oldValue.getClass().getName());
        }
        return oldValue;
    }

    @Override
    protected void checkCompatibility(DataType fieldType) {
        if (!(fieldType instanceof NumericDataType)) {
            throw new UnsupportedOperationException("Expected numeric type, got " + fieldType.getName() + ".");
        }
    }

    private double calculate(Number operand2) {
        switch (operator) {
            case ADD:
                return operand2.doubleValue() + operand.getDouble();
            case DIV:
                return operand2.doubleValue() / operand.getDouble();
            case MUL:
                return operand2.doubleValue() * operand.getDouble();
            case SUB:
                return operand2.doubleValue() - operand.getDouble();
        }
        return 0d;
    }

    @Override
    public void serialize(DocumentUpdateWriter data, DataType superType) {
        data.write(this);
    }

    @Override
    public boolean equals(Object o) {
        return o instanceof ArithmeticValueUpdate && super.equals(o) &&
                operator == ((ArithmeticValueUpdate) o).operator && operand.equals(((ArithmeticValueUpdate) o).operand);
    }

    @Override
    public int hashCode() {
        return super.hashCode() + operator.hashCode() + operand.hashCode();
    }

    @Override
    public String toString() {
        return super.toString() + " " + operator.name + " " + operand;
    }

    /**
     * Lists valid operations that can be performed by an ArithmeticValueUpdate.
     */
    public enum Operator {
        /**
         * Add the operand to the value.
         */
        ADD(0, "add"),
        /**
         * Divide the value by the operand.
         */
        DIV(1, "divide"),
        /**
         * Multiply the value by the operand.
         */
        MUL(2, "multiply"),
        /**
         * Subtract the operand from the value.
         */
        SUB(3, "subtract");

        /**
         * The numeric ID of the operator, used for serialization.
         */
        public final int id;
        /**
         * The name of the operator, mainly used in toString() methods.
         */
        public final String name;

        Operator(int id, String name) {
            this.id = id;
            this.name = name;
        }

        /**
         * Returns the operator with the specified ID.
         *
         * @param id the ID to search for
         * @return the Operator with the specified ID, or null if it does not exist.
         */
        public static Operator getID(int id) {
            for (Operator operator : Operator.values()) {
                if (operator.id == id) {
                    return operator;
                }
            }
            return null;
        }
    }
}