All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.epam.deltix.qsrv.hf.codec.cg.QAccessMethod Maven / Gradle / Ivy

/*
 * Copyright 2021 EPAM Systems, Inc
 *
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership. 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.epam.deltix.qsrv.hf.codec.cg;

import com.epam.deltix.qsrv.hf.pub.codec.FieldLayout;
import com.epam.deltix.qsrv.hf.pub.codec.NonStaticFieldLayout;
import com.epam.deltix.qsrv.hf.pub.codec.StaticFieldLayout;
import com.epam.deltix.qsrv.hf.pub.md.BooleanDataType;
import com.epam.deltix.util.jcg.JCompoundStatement;
import com.epam.deltix.util.jcg.JExpr;
import com.epam.deltix.util.jcg.JLocalVariable;
import com.epam.deltix.util.jcg.JStatement;

import static com.epam.deltix.qsrv.hf.tickdb.lang.compiler.cg.QCGHelpers.CTXT;

/**
 * Accessor for new message format with get/set/nullify/has methods
 */
public class QAccessMethod  implements QAccessor{
    // reference to an object instance
    private final JExpr reference;

    private final String fieldName;
    private final String fieldSchemaName;
    private final String fieldDescription;
    private final QPrimitiveType type;

    private final String getterName;
    private final String setterName;
    private final String nullifierName;
    private final String haserName;

    public final boolean hasSmartProperties;

    private final FieldLayout layout;

    public QAccessMethod(JExpr reference, FieldLayout layout, QPrimitiveType type ) {
        this.reference = reference;
        this.type      = type;
        this.layout    = layout;

        this.fieldDescription = layout.getDescription();

        this.getterName =      layout.hasAccessMethods() ? layout.getGetter().getName() : null;
        this.setterName =      layout.hasAccessMethods() ? layout.getSetter().getName() : null;

        // name in rcd can be incorrect for compiled codecs. If getter exists - use it name
        this.fieldName = layout.hasAccessMethods() ? extractName(layout.getGetter().getName()) : layout.getName();
        this.fieldSchemaName = layout.getName();

        this.nullifierName =  layout.hasSmartProperties() ? layout.getNullifier().getName() : null;
        this.haserName =      layout.hasSmartProperties() ? layout.getHaser().getName() : null;

        this.hasSmartProperties = layout.hasSmartProperties();
    }

    private String extractName(String getterName) {
        String getterNameLowerCase = getterName.toLowerCase();
        if (getterNameLowerCase.startsWith("get"))
            return toJavaNotation(getterName.substring(3));
        else if (getterNameLowerCase.startsWith("is"))
            return toJavaNotation(getterName.substring(2));
        else return getterName;
    }

    private String toJavaNotation(String name) {
        return Character.toLowerCase(name.charAt(0)) + name.substring(1);
    }

    JExpr readAtomicNoCast() {
        return reference.call(getterName);
    }

    @Override
    public JExpr read() {
        if (type.dt instanceof BooleanDataType) {
            if (type.dt.isNullable()) { // return param for out.writeByte();
                if (layout.getGetterReturnType() ==  boolean.class && layout.hasSmartProperties())
                    return CTXT.condExpr(haser(), castBooleanToByte(readAtomicNoCast()), CTXT.intLiteral(-1).cast(byte.class));
                else if (layout.getGetterReturnType() ==  byte.class)
                    return readAtomicNoCast();
                else throw new UnsupportedOperationException("Can`t read NULLABLE BOOLEAN using getter: \"" + getterName + "()\" that return boolean.class without HASER method.");
            } else { //not nullable case. return param for out.writeBoolean();
                return (layout.getGetterReturnType() ==  boolean.class) ?
                        readAtomicNoCast() : castByteToBoolean(readAtomicNoCast());
            }
        }

        return  readAtomicNoCast();
    }

    private JExpr castByteToBoolean(JExpr arg) {
        return CTXT.binExpr(arg,
                "==",
                CTXT.intLiteral(1).cast(byte.class)
        );
    }

    private JExpr castBooleanToByte(JExpr arg) {
        return CTXT.condExpr(arg,
                        CTXT.intLiteral(1).cast(byte.class),
                        CTXT.intLiteral(0).cast(byte.class)
                );
    }

    private JExpr haser() {
        return reference.call(haserName);
    }

    public JExpr haser(boolean eq) {
        return haserName != null ?
                (eq ? reference.call(haserName).not() : reference.call(haserName)) :
                CTXT.binExpr(reference.call(getterName), eq ? "==" : "!=", type.getNullLiteral());
    }

    @Override
    public JStatement writeNullify(JExpr nullExpr) {
        return nullifierName != null ?
                reference.call(nullifierName).asStmt() :
                reference.call(setterName, nullExpr).asStmt();
    }

    @Override
    public String getSchemaFieldName () {
        return fieldSchemaName;
    }

    @Override
    public Class getFieldType () {
        // using for cast in set static value
        return layout.getSetterType();
    }

    @Override
    public JStatement write(JExpr arg) {
        if (type.dt instanceof BooleanDataType && layout instanceof NonStaticFieldLayout) {
            if (!type.dt.isNullable()) {  // arg = in.readBoolean ()
                return layout.getSetterType() == boolean.class ?
                        reference.call(setterName, arg).asStmt() :
                        reference.call(setterName, castBooleanToByte(arg)).asStmt();

            } else { // arg = in.readByte ()
                if (layout.getSetterType() == byte.class) {
                    return reference.call(setterName, arg).asStmt();
                } else if (layout.getSetterType() == boolean.class && layout.hasSmartProperties()) {
                    JCompoundStatement statement = CTXT.compStmt();
                    JLocalVariable variable = statement.addVar(0, byte.class, "value", arg);
                    statement.add(CTXT.ifStmt(
                            CTXT.binExpr(variable, "==", CTXT.intLiteral(BooleanDataType.NULL)),
                            writeNullify(null),
                            reference.call(setterName, castByteToBoolean(variable)).asStmt()
                    ));
                    return statement;
                } else
                    throw new UnsupportedOperationException("Can`t write NULLABLE BOOLEAN using setter: \"" + setterName + "()\" that parameter type = boolean.class without NULLIFIER method.");
            }
        } else if (type.dt instanceof BooleanDataType &&
                layout instanceof StaticFieldLayout &&
                layout.hasSmartProperties() &&
                layout.getSetterType() == boolean.class &&
                (((StaticFieldLayout) layout).getField()).getStaticValue() == null) {
            return writeNullify(null);
        }

        return reference.call(setterName, arg).asStmt();
    }


    @Override
    public String getFieldName() {
        return fieldName;
    }

    @Override
    public String getFieldDescription() {
        return fieldDescription;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy