Package cn.wensiqun.asmsupport.operators.array

Source Code of cn.wensiqun.asmsupport.operators.array.ArrayValue$EachValue

/**
*
*/
package cn.wensiqun.asmsupport.operators.array;

import java.lang.reflect.Array;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import cn.wensiqun.asmsupport.Parameterized;
import cn.wensiqun.asmsupport.asm.InstructionHelper;
import cn.wensiqun.asmsupport.block.ProgramBlock;
import cn.wensiqun.asmsupport.clazz.AClass;
import cn.wensiqun.asmsupport.clazz.ArrayClass;
import cn.wensiqun.asmsupport.operators.AbstractOperator;
import cn.wensiqun.asmsupport.utils.AClassUtils;

/**
* @author 温斯群(Joe Wen)
*
*/
public class ArrayValue extends AbstractOperator implements Parameterized  {

    private static Log log = LogFactory.getLog(ArrayValue.class);
   
    private abstract class EachValue{
       
        private Object array;
       
        private EachValue(Object array){
            this.array = array;
        }
       
        int process(){
          if(array != null){
              return loopProcess(this.array, 0);
            }
            return 0;
        }
       
        private int loopProcess(Object object, int over){
          if(object.getClass().isArray()){
              int len = Array.getLength(object);
            int preArrayDoor = -1;
              for(int i=0; i<len; i++){
              Object o = Array.get(object, i);
              int curArrayDoor = loopProcess(o, over + 1);
              if(preArrayDoor == -1 || preArrayDoor == curArrayDoor){
                preArrayDoor = curArrayDoor;
              }else if(preArrayDoor != curArrayDoor){
                        throw new IllegalArgumentException("This array exist different dim sub-array : " + ArrayUtils.toString(this.array));
              }
            }
            return preArrayDoor == - 1 ? over + 1 : preArrayDoor;
          }else{
            try{
                    process((Parameterized) object);
                }catch(ClassCastException e){
                  throw new IllegalArgumentException("exception occur when " + ArrayValue.this.toString(), e);
                }
              return over;
          }
        }
       
        abstract void process(Parameterized para);
       
    }
   
    private ArrayClass arrayCls;
    private Parameterized[] allocateDims;
    //it's array by reflect to parse
    private Object values;
   
    private boolean useByOther;
   
    private void batchAsArgument(Object values){
        new EachValue(values){
            @Override
            void process(Parameterized para) {
                para.asArgument();   
            }
           
        }.process();
    }
   
    protected ArrayValue(ProgramBlock block, ArrayClass arrayCls, Parameterized... allocateDims) {
        super(block);
        if(arrayCls.getDimension() < allocateDims.length){
            throw new IllegalArgumentException("dimension not enough: array type is " + arrayCls + " and allocate dims is " + ArrayUtils.toString(allocateDims));
        }
        this.arrayCls = arrayCls;
        this.allocateDims = allocateDims;
    }
   
    /**
     *
     * @param block
     * @param arrayCls
     * @param values Parameterized array
     */
    protected ArrayValue(ProgramBlock block, ArrayClass arrayCls, Object values) {
        super(block);
        this.arrayCls = arrayCls;
        this.values = values;
      if(values != null && !values.getClass().isArray()){
        throw new IllegalArgumentException("values must be an array");
      }else{
        //check verify
        int dim = new EachValue(values){
        @Override
        void process(Parameterized para) {}
        }.process();
        if(arrayCls.getDimension() != dim){
                throw new IllegalArgumentException("different dimension : value dimension is " + dim + ", class(" + arrayCls + ") dimension is " + arrayCls.getDimension());
        }
      }
    }

    @Override
    protected void firstPrepareProcess() {
    }

    @Override
    protected void beforeInitProperties() {
    }

    @Override
    protected void verifyArgument() {
      //当调用ArrayValue(ProgramBlock block, ArrayClass arrayCls, Parameterized... allocateDims)构造方法
      if(allocateDims != null){
            for(Parameterized dim : allocateDims){
                int order = AClassUtils.getPrimitiveAClass(dim.getParamterizedType()).getCastOrder();
                if(order > AClass.INT_ACLASS.getCastOrder() ||
                   order <= AClass.BOOLEAN_ACLASS.getCastOrder()){
                    throw new RuntimeException("the allcate dim number must be byte, char, short or int type!");
                }
            }
        }

      //当调用其他构造方法
      final AClass rootComp = arrayCls.getRootComponentClass();
        new EachValue(values){
            @Override
            void process(Parameterized para) {
              AClassUtils.autoCastTypeCheck(para.getParamterizedType(), rootComp);
            }
           
        }.process();
    }

    @Override
    protected void checkOutCrement() {
    }

    @Override
    protected void checkAsArgument() {
        batchAsArgument(allocateDims);
        batchAsArgument(values);
    }

    @Override
    protected void afterInitProperties() {
    }

    @Override
    protected void lastPrepareProcess() {
    }
   
    private void loopArray(AClass acls, Object arrayOrElement){
        InstructionHelper ih = block.getInsnHelper();
        if(arrayOrElement.getClass().isArray()){
            int len = Array.getLength(arrayOrElement);
            ih.push(len);
            AClass nextDimType = ((ArrayClass)acls).getNextDimType();
            ih.newArray(nextDimType.getType());
            if(len > 0){
                ih.dup()
            }
            for(int i=0; i<len ;i++){
                ih.push(i);
                loopArray(nextDimType, Array.get(arrayOrElement, i));
                ih.arrayStore(acls.getType());
                if(i < len - 1){
                    ih.dup();
                }
            }
        }else{
            ((Parameterized) arrayOrElement).loadToStack(block);
            //auto cast each value for array
            autoCast(((Parameterized)arrayOrElement).getParamterizedType(), acls);
        }
    }

    @Override
    protected void executing() {
        if(!useByOther){
            throw new RuntimeException("this array value not use by other operator");
        }
       
        if(allocateDims != null){
            log.debug("start new a array!");
            InstructionHelper ih = block.getInsnHelper();
            if(allocateDims == null || allocateDims.length == 0){
                ih.push(arrayCls.getType());
                ih.checkCast(arrayCls.getType());
                return;
            }
           
            if(allocateDims.length == 1){
                allocateDims[0].loadToStack(block);
                ih.unbox(allocateDims[0].getParamterizedType().getType());
                ih.newArray(arrayCls.getNextDimType().getType());
            }else{
                for(Parameterized allocate : allocateDims){
                    allocate.loadToStack(block);
                    ih.unbox(allocate.getParamterizedType().getType());
                }
                ih.multiANewArrayInsn(arrayCls.getType(), allocateDims.length);
            }
        }else{
            loopArray(arrayCls, values);
        }
    }

    @Override
    public void loadToStack(ProgramBlock block) {
        this.execute();
    }

    @Override
    public AClass getParamterizedType() {
        return arrayCls;
    }

    @Override
    public void asArgument() {
        useByOther = true;
        block.removeExe(this);
    }

  @Override
  public String toString() {
    return "new " + arrayCls.toString() + " " + super.toString();
  }

   
}
TOP

Related Classes of cn.wensiqun.asmsupport.operators.array.ArrayValue$EachValue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.