Package erjang

Source Code of erjang.EBitStringBuilder

/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2009 by Trifork
*
* 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 erjang;

import java.math.BigInteger;

import erjang.driver.IO;

/**
*
*/
public class EBitStringBuilder {

  public static final int PB_IS_WRITABLE = 1;
  public static final int PB_ACTIVE_WRITER = 2;
 
  EBitString bs;
  int byte_pos;
  int extra_bits;
  byte[] data;
  byte flags;
 
  /**
   * @param byte_size
   * @param flags
   */
  public EBitStringBuilder(int byte_size, int flags) {
    this.flags = (byte) flags;
    data = new byte[byte_size];
    bs = EBitString.make(data, 0, byte_size, 0);
  }

  public static
  EBitStringBuilder bs_init_writable(EObject size) {
    int bin_size = 1024;
    ESmall sz = size.testSmall();
    if (sz != null && sz.value >= 0) {
      bin_size = sz.value;
    }
     
    EBitStringBuilder res = new EBitStringBuilder(bin_size, PB_IS_WRITABLE|PB_ACTIVE_WRITER);
   
    return res;
  }
 
  public EBitStringBuilder(int byte_size, int extra_bits, int flags) {
    if (flags != 0) throw new NotImplemented("flags="+flags);
    data = new byte[byte_size+(extra_bits>0?1:0)];
    bs = EBitString.make(data, 0, byte_size, extra_bits);
  }

  /** return bitstring under construction */
  public EBitString bitstring() {
    if ((flags & PB_IS_WRITABLE) == PB_IS_WRITABLE)
      bs.byte_size = this.byte_pos;
    return bs;
  }

  public void put_float(EObject value, int bit_size, int flags) {
    if (extra_bits != 0)
      throw new NotImplemented();

    switch (bit_size) {
    case 32: {
      ENumber en = value.testNumber();
      if (en==null) { throw ERT.badarg(value); }
      float val = (float)en.doubleValue();
      put_int32(Float.floatToIntBits(val), flags);
      return;
    }
    case 64: {
      ENumber en = value.testNumber();
      if (en==null) { throw ERT.badarg(value); }
      double val = en.doubleValue();
      put_int64(Double.doubleToLongBits(val), flags);
      return;
    }
    } // switch

    throw new NotImplemented("val="+value+";size="+bit_size+";flags="+flags);
  }

  public void put_integer(EObject value, int flags) {
    throw new NotImplemented("val="+value+";flags="+flags);
  }

  public void put_integer(EObject value, int bit_size, int flags) {
    boolean litteEndian = (flags & EBinMatchState.BSF_LITTLE) > 0;

    EInteger ei = value.testInteger();
    if (ei==null) throw ERT.badarg(value);

    if (bit_size == 8 && extra_bits==0) { // Common case optimization
      data[byte_pos++] = (byte)ei.intValue();
      return;
    }

    ESmall sm = value.testSmall();

    if (extra_bits == 0 && (bit_size % 8) == 0) {
      int nBytes = bit_size/8;

      // We process the bytes little-endian:
      int pos, delta;
      if (litteEndian) {
        pos = byte_pos;
        delta = 1;
      } else{
        pos = byte_pos + nBytes-1;
        delta = -1;
      }
      byte_pos += nBytes;

      if (sm!=null) { // ESmall case
        int val = sm.intValue();
        while (nBytes-- > 0) {
          data[pos] = (byte)val;
          pos += delta;
          val >>= 8;
        }
        } else { // Larger integer case
        BigInteger big_int = ei.bigintValue();

        byte[] bytes = big_int.toByteArray();
        int src_pos = bytes.length;
        while (--src_pos >= 0 && nBytes-- > 0) {
          data[pos] = bytes[src_pos];
          pos += delta;
        }
        if (nBytes > 0) {
          byte sign_byte = (byte)(big_int.signum() < 0 ? -1 : 0);
          while (nBytes-- > 0) {
            data[pos] = sign_byte;
            pos += delta;
          }
        }
      }
     
      return;
    }
   
    if (bit_size <= 32 && (bit_size % 8) != 0) {
      int val = sm.value;
      if (litteEndian)
        throw new NotImplemented();
     
      int bits_left_in_current_byte = 8-extra_bits;
      int msb_bits = Math.min(bits_left_in_current_byte, bit_size);
      int lsb_bits = bit_size-msb_bits;
     
      while (lsb_bits + msb_bits > 0) {
        int mask = ((1 << msb_bits) - 1);
        int putval = ((val >>> lsb_bits) & mask) << (8-msb_bits);
        int getval = data[byte_pos];
       
        assert ((putval & getval) == 0);
       
        data[byte_pos] = (byte) (putval | getval);

        extra_bits = (extra_bits + msb_bits) % 8;
        if (extra_bits == 0) {
          byte_pos += 1;
        }
               
        lsb_bits -= msb_bits;
        msb_bits = Math.min(8, lsb_bits);
      }
     
      return;
    }
   
    EBig bi = value.testBig();
    if (bit_size <= 64 && (bit_size % 8) != 0) {
      long val = bi == null
        ? sm.longValue()
        : bi.longValue();
      if (litteEndian)
        throw new NotImplemented();
     
      int bits_left_in_current_byte =
        (extra_bits == 0
            ? 8
            : 8-extra_bits);

      int msb_bits = Math.min(bits_left_in_current_byte, bit_size);
      int lsb_bits = bit_size-msb_bits;
     
      while(lsb_bits + msb_bits > 0) {
        int mask = ((1 << msb_bits) - 1);
        int putval = (int) ((val >>> lsb_bits) & mask);
        int getval = data[byte_pos] & ~mask;
       
        assert ((putval & getval) == 0);
       
        data[byte_pos] = (byte) (putval | getval);

        extra_bits = (extra_bits + msb_bits) % 8;
        if (extra_bits == 0) {
          byte_pos += 1;
        }
               
        lsb_bits -= msb_bits;
        msb_bits = Math.min(8, lsb_bits);
      };
     
      return;
    }
   
    throw new NotImplemented("put_integer value="+ value +"; bit_size="+  bit_size + "; flags=" + flags);
   
  }

  protected void put_int64(long val, int flags) {
    if ((flags & EBinMatchState.BSF_LITTLE) > 0) {
      put_int32_little((int)val);
      put_int32_little((int)(val>>32));
    } else {
      put_int32_big((int)(val>>32));
      put_int32_big((int)val);
    }
  }

  protected void put_int32(int val, int flags) {
    if ((flags & EBinMatchState.BSF_LITTLE) > 0) {
      put_int32_little(val);
    } else {
      put_int32_big(val);
    }
  }

  protected void put_int32_little(int val) {
    byte b1, b2, b3, b4;
    b1 = (byte)val; val >>= 8;
    b2 = (byte)val; val >>= 8;
    b3 = (byte)val; val >>= 8;
    b4 = (byte)val;
    put_byte(b1);
    put_byte(b2);
    put_byte(b3);
    put_byte(b4);
  }

  protected void put_int32_big(int val) {
    byte b1, b2, b3, b4;
    b4 = (byte)val; val >>= 8;
    b3 = (byte)val; val >>= 8;
    b2 = (byte)val; val >>= 8;
    b1 = (byte)val;
    put_byte(b1);
    put_byte(b2);
    put_byte(b3);
    put_byte(b4);
  }
 
  protected void put_int16(int val, int flags) {
    if ((flags & EBinMatchState.BSF_LITTLE) > 0) {
      put_int16_little(val);
    } else {
      put_int16_big(val);
    }
  }

  protected void put_int16_little(int val) {
    byte b1, b2;
    b1 = (byte)val; val >>= 8;
    b2 = (byte)val;
    put_byte(b1);
    put_byte(b2);
  }

  protected void put_int16_big(int val) {
    byte b1, b2;
    b2 = (byte)val; val >>= 8;
    b1 = (byte)val;
    put_byte(b1);
    put_byte(b2);
  }
 
  private void put_byte(byte val) {
   
    if (extra_bits == 0) {
      data[byte_pos++] = val;
      return;
     
    } else {
     
      // | bits1 : bits2 |

      int bits1 = extra_bits;
      int bits2 = 8-bits1;

      data[byte_pos] |= (byte)((0xff & val) >> bits1);
      data[byte_pos+1] = (byte) ((val & ((1<<bits1)-1)) << bits2);
     
      byte_pos += 1;
    }

}

  public void put_string(EString str) {
    if (extra_bits != 0)
    {
      for (int i = 0; i < str.length(); i++) {
        put_byte(str.data[str.off+i]);
      }
      return;
    }
    System.arraycopy(str.data, str.off, data, byte_pos, str.length());
    byte_pos += str.length();
  }
 
  /** grow a bitstring by extra_size bits, and return a string builder with position at end of original bitstring */
  public static EBitStringBuilder bs_private_append(EObject str_or_builder, int extra_size, int unit, int flags)
  {
    EBitString ebs = str_or_builder.testBitString();
    if (ebs == null) throw new NotImplemented();
   
    long bitSize = ebs.bitSize() + extra_size;
    int size = (int) (bitSize/8);
    int extra = (int) (bitSize % 8);
   
    EBitStringBuilder result = new EBitStringBuilder(size, extra, flags);
    System.arraycopy(ebs.data, ebs.byteOffset(), result.data, 0, ebs.dataByteSize());
   
    result.byte_pos = ebs.byteSize();
    result.extra_bits = ebs.extra_bits;
   
    return result;
  }


  /** grow a bitstring by extra_size bits, and return a string builder with position at end of original bitstring */
  public static EBitStringBuilder bs_append(EObject str_or_builder, int extra_size, int unit, int flags)
  {
    EBitString ebs = str_or_builder.testBitString();
    if (ebs == null) throw new NotImplemented();
   
    long bitSize = ebs.bitSize() + extra_size;
    int size = (int) (bitSize/8);
    int extra = (int) (bitSize % 8);
   
    EBitStringBuilder result = new EBitStringBuilder(size, extra, flags);
    System.arraycopy(ebs.data, ebs.byteOffset(), result.data, 0, ebs.dataByteSize());
   
    result.byte_pos = ebs.byteSize();
    result.extra_bits = ebs.extra_bits;
   
    return result;
  }

  /** Append a bit string.
   *  @param size The output size in bits; -1 means the entire bitstring.
   */
  public void put_bitstring(EObject str, int size, int flags) {
    EBitString ebs = str.testBitString();
    if (ebs == null) throw new InternalError("bad code gen, arg is "+str.getClass());
   
    if (extra_bits != 0)
      throw new NotImplemented();
   
    if (size != -1 && size != ebs.bitSize()) {
      throw new NotImplemented();
    }
   
    System.arraycopy(ebs.data, ebs.byteOffset(), data, byte_pos, ebs.totalByteSize());
    byte_pos += ebs.byteSize();
    extra_bits += ebs.extra_bits; // TODO on extension
  }
 
  public void put_utf8(EObject value, int flags) {
   
    ESmall sm;
    if ((sm=value.testSmall()) != null && sm.value >= 0 && sm.value < 0x110000) {

      if (sm.value < 0x80) {
        put_byte((byte) sm.value);
        return;
      }
     
      if (sm.value < 0x0800) {
        put_byte((byte) (0xc0 | ((sm.value >> 6) & 0x1f)));
        put_byte((byte) (0x80 | (sm.value        & 0x3f)));
        return;
      }
 
      if (sm.value < 0x10000) {
        put_byte((byte) (0xe0 | ((sm.value >> 12) & 0x0f)));
        put_byte((byte) (0x80 | ((sm.value >> 6& 0x3f)));
        put_byte((byte) (0x80 | (sm.value         & 0x3f)));
        return;
      }

      if (sm.value < 0x110000) {
        put_byte((byte) (0xf0 | ((sm.value >> 18) & 0x7)));
        put_byte((byte) (0x80 | ((sm.value >> 12) & 0x3f)));
        put_byte((byte) (0x80 | ((sm.value >> 6& 0x3f)));
        put_byte((byte) (0x80 | (sm.value         & 0x3f)));
        return;
      }
    }

   
    throw ERT.badarg(value);
  }

  public void put_utf16(EObject value, int flags) {
    ESmall num = value.testSmall();
    if (num == null
        || num.value < 0
        || num.value > 0x10FFFF
        || (0xD800 <= num.value && num.value <= 0xDFFF)) {
      throw ERT.badarg(value);
    }
   
    if (num.value < 0x10000) {
      put_int16(num.value, flags);
    } else {
      int low = num.value - 0x10000;
      int num1 = 0xD800 | ((low >> 10) & 0x3ff);
      int num2 = 0xDC00 | (low & 0x3ff);
      put_int16(num1, flags);
      put_int16(num2, flags);
    }
  }

  public void put_utf32(EObject value, int flags) {
    ESmall num = value.testSmall();
    if (num == null || !Character.isDefined(num.value))
      throw ERT.badarg(value); // TODO: throw what?
    String val = new String(new char[] { (char) num.value });
    byte[] bytes = val.getBytes(IO.UTF32);
    for (int i = 0; i < bytes.length; i++) {
      put_byte(bytes[i]);
    }
  }

  // compute size of utf8 char
  static public ESmall bs_utf8_size(EObject value) {
    ESmall sm;
    if ((sm=value.testSmall()) != null) {
     
      if (sm.value < 0) return null;
      if (sm.value < 0x80) return ERT.box(1);
      if (sm.value < 0x800) return ERT.box(2);
      if (sm.value < 0x10000) return ERT.box(3);
      if (sm.value < 0x200000) return ERT.box(4);
      if (sm.value < 0x4000000) return ERT.box(5);
      return ERT.box(6);
    }
   
    return null;
  }
 
  // compute size of utf16 char
  static public ESmall bs_utf16_size(EObject value) {
    ESmall num = value.testSmall();
    if (num == null || num.value < 0)
      return null;
    if (num.value < 0x10000) return ERT.box(2);
    return ERT.box(4);
  }
}
TOP

Related Classes of erjang.EBitStringBuilder

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.