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

ch.ethz.globis.phtree.util.BitsShort Maven / Gradle / Ivy

There is a newer version: 2.8.1
Show newest version
/*
 * Copyright 2011-2016 ETH Zurich. All Rights Reserved.
 *
 * This software is the proprietary information of ETH Zurich.
 * Use is subject to license terms.
 */
package ch.ethz.globis.phtree.util;


/**
 * Bit-stream manipulation functions.
 * 
 * @author ztilmann
 *
 */
public class BitsShort {

    private static final int UNIT_3 = 4;  			//EXP: 2^EXP = BITS
    private static final int UNIT_BITS = (1<>> UNIT_3;
        int startBit = UNIT_BITS -(offsetBit & UNIT_0x07);  //last three bit [0..7]
        long ret = 0;
        int bitsRead = 0;
        while (bitsRead < entryLen) {
            long mask = (1L << startBit)-1L;
            if (bitsRead+startBit > entryLen) {
                int bitsToIgnore = bitsRead + startBit - entryLen;
                long mask2 = (1L<>> bitsToIgnore;
            } else {
                bitsRead += startBit;
                ret <<= UNIT_BITS;
                ret |= ba[pA] & mask;
            }
            startBit = UNIT_BITS;
            pA++;
        }
        return ret;
    }

    public static void writeArray(short[] ba, int offsetBit, int entryLen, long val) {
        int pA = offsetBit >>> UNIT_3;
        int startBit = UNIT_BITS - (offsetBit & UNIT_0x07); //counting from right to left (low to high)
        int bitsWritten = 0;
        while (bitsWritten < entryLen) {
            //int mask = (1 << startBit)-1;
            //erase byte[] first - create mask
            long eraseMask = (1L << startBit) - 1L;
            int bitsToWrite = startBit;
            if (bitsWritten+bitsToWrite > entryLen) {
                int bitsToIgnore = bitsWritten + startBit - entryLen;
                long mask2 = (1L< 0 ? val >>> toShift : val << (-toShift);
            //this cuts of any leading bits
            long maskToCutOfHeadingBits = (1L << startBit) - 1L;
            infTemp &= maskToCutOfHeadingBits;
            ba[pA] |= infTemp;
            bitsWritten += bitsToWrite; //may have been less, but in that case we quit anyway
            startBit = UNIT_BITS;
            pA++;
        }
    }

	/**
	 * 
	 * @param ba byte array
	 * @param start start bit
	 * @param nBits amount to shift, positive to right, negative to left.
	 */
    public static void insertBits1(short[] ba, int start, int nBits) {
		if (nBits == 0) {
			return;
		}
		if (nBits < 0) {
			throw new IllegalArgumentException();
		}
		statOldRightShift++;
		long t1 = System.currentTimeMillis();
		//shift right
//		copyBits(ba2, start, ba2, start + nBits, ba2.length*8-start-nBits);
		int bitsToShift = ba.length*UNIT_BITS - start - nBits;
		for (int i = 0; i < bitsToShift; i++) {
			int srcBit = ba.length*UNIT_BITS - nBits - i - 1;
			int trgBit = ba.length*UNIT_BITS - i - 1;
			setBit(ba, trgBit, getBit(ba, srcBit));
		}
		long t2 = System.currentTimeMillis();
		statOldRightShiftTime += (t2-t1);
	}

    /**
     * Insert bits at the given position. 
     * 
     * The resulting array is NOT resized, bit that do do not fit in the current array are lost.  
	 * @param ba byte array
	 * @param start start bit
     * @param nBits number of bits
     */
    public static void insertBits(short[] ba, int start, int nBits) {
		if (nBits == 0) {
			return;
		}
		if (nBits < 0) {
			throw new IllegalArgumentException();
		}
		statOldRightShift++;
		long t1 = System.currentTimeMillis();
		//shift right
		//TODO Improve this. We now shift right by too much, then shift back left.
		//bytes to insert (not to move!)
		int nBytes = (int) Math.ceil(nBits/(double)UNIT_BITS);
		int startByte = start>>UNIT_3;
		int bytesToCopy = ba.length - (startByte+nBytes);
		short tmp = ba[ba.length-nBytes];
		if (bytesToCopy != 0) {
			//move right by some bytes/shorts
			System.arraycopy(ba, startByte, ba, startByte + nBytes, bytesToCopy);
			//move back left
			int nBitsToMoveLeft = nBytes*UNIT_BITS-nBits;
//			System.out.println("IB: s=" + start + " nBits=" + nBits + " nBLeft = " + nBitsToMoveLeft + "  baLen=" + ba.length);
			removeBits(ba, start+nBits, nBitsToMoveLeft);
			//apply tmp
			int offs = UNIT_BITS-nBitsToMoveLeft;
			copyBitsLeft(new short[]{tmp}, 0, ba, (ba.length-1)*UNIT_BITS+offs, nBitsToMoveLeft);
		} else {
			//Must be last byte in array
			//apply tmp
			int offsTmp = start&UNIT_0x07;
			//check if we should copy at all. If everything is shifted out of the array, then we 
			//don't need to copy anything.
			if (start+nBits < ba.length*UNIT_BITS) {
				int offsTrg = (start+nBits)&UNIT_0x07;
				int len = UNIT_BITS - offsTrg;
//				System.out.println("IB: s=" + start + " nBits=" + nBits + "  baLen=" + ba.length);
//				System.out.println("IB: oTmp=" + offsTmp + " oTrg=" + offsTrg + "  len=" + len + "  " + ((ba.length-1)*UNIT_BITS + offsTrg));
				copyBitsLeft(new short[]{tmp}, offsTmp, ba, (ba.length-1)*UNIT_BITS + offsTrg, len);
			}
		}

		long t2 = System.currentTimeMillis();
		statOldRightShiftTime += (t2-t1);
    }
    
    public static void removeBits(short[] ba, int start, int nBits) {
		if (nBits == 0) {
			return;
		}
		if (nBits < 0) {
			throw new IllegalArgumentException("nBits = " + nBits);
		}
		//shift left
		copyBitsLeft(ba, start + nBits, ba, start, ba.length*UNIT_BITS-start-nBits);
//		int bitsToShift = ba.length*8 - start - (nBits);
//		for (int i = 0; i < bitsToShift; i++) {
//			int srcBit = start + (nBits) + i;
//			int trgBit = start + i;
//			setBit(ba, trgBit, getBit(ba, srcBit));
//		}
	}

    public static void copyBitsLeft(short[] src, int posSrc, short[] trg, int posTrg) {
    	int len = src.length*UNIT_BITS-posSrc;
    	copyBitsLeft(src, posSrc, trg, posTrg, len);
    }
    	
    public static void copyBitsLeft(short[] src, int posSrc, short[] trg, int posTrg, int len) {
    	if (len==0) {
    		return;
    	}
    	final boolean DBG = false; //TODO
    	if (posSrc < 0 || posTrg < 0) {
    		throw new IllegalArgumentException("s=" + posSrc + " t=" + posTrg);
    	}
    	if (posSrc + len > src.length*UNIT_BITS || posTrg + len > trg.length*UNIT_BITS) {
    		throw new IllegalArgumentException("s=" + posSrc + " t=" + posTrg + " len=" + len + 
    				"  srcLen/trgLen = " + src.length + " / " + trg.length + " // " + UNIT_BITS);
    	}
    	long buf = 0;
        int psA = posSrc >>> UNIT_3;
        int startBitS = UNIT_BITS - (posSrc & UNIT_0x07); //counting from right to left (low to high) [8..1]
        int ptA = posTrg >>> UNIT_3;
        int startBitT_lr = (posTrg & UNIT_0x07); //counting from left to right, [0..7];
        int startBitT = UNIT_BITS - (posTrg & UNIT_0x07); //counting from right to left (low to high) [8..1]
    	
        int bitsInBuffer = 0;
        final int bitsToCopy = len;
        int bitsRead = 0;
        int bitsWritten = 0;
        
    	//read bits of half-used byte into buffer
    	if (startBitS != UNIT_BITS) {
            long mask = (1L << startBitS)-1L;
            buf |= src[psA] & mask;
            if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
            bitsInBuffer = startBitS;
            bitsRead = startBitS;
            psA++;
            if (bitsRead > bitsToCopy) {
            	buf >>>= (bitsRead - bitsToCopy);
            	bitsRead = bitsToCopy;
            	bitsInBuffer = bitsToCopy;
            }
    	}
    	
    	//erase-mask for setting target-bits to 0 (necessary for overwriting via OR/|=)
        long eraseMask = (1L << startBitT) - 1L;
        eraseMask = ~eraseMask;  // 00 for all bit that need overwriting.
        if (DBG) System.out.println("em=" + toBinary(eraseMask));  //TODO
        int bitsToWriteThisRound = startBitT < len ? startBitT : len;
    	
    	//main loop - traverses everything but the last byte
        boolean readingFinished = false;
        boolean writingFinished = false;
        while (!(readingFinished && writingFinished) ) {
    	//while (bitsWritten <= bitsToCopy && !readingFinished) {
    		//read into buffer
        	if (bitsRead < bitsToCopy) {
	    		buf <<= UNIT_BITS;
	            if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
	            if (DBG) System.out.println("src=" + toBinary(src[psA]));  //TODO
	    		buf |= src[psA] & UNIT_0xFF; //Otherwise leading bits may be 111111111
	    		if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
	    		bitsRead += UNIT_BITS;
	    		bitsInBuffer += UNIT_BITS;
	            if (bitsRead >= bitsToCopy) {
	            	readingFinished = true;
	            	if (bitsRead > bitsToCopy) {
		            	int d = bitsRead - bitsToCopy;
		            	buf >>>= d;
	        			if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
		            	bitsRead -= d;
		            	bitsInBuffer -= d;
	            	}
	            }
        	} else {
        		readingFinished = true;
        	}
    		
    		
    		//write
           	//Only write, if last written bit is last bit of current byte. ->End-aligned.
        	if (startBitT_lr + bitsInBuffer < UNIT_BITS) {
        		break;
        	}
        	
        	long buf2 = buf;
            if (DBG) System.out.println("buf2=" + toBinary(buf));  //TODO

            buf2 >>>= bitsInBuffer-bitsToWriteThisRound; 
        	if (bitsToWriteThisRound > bitsInBuffer) {
        		buf2 = buf << (bitsToWriteThisRound-bitsInBuffer);
        		eraseMask = ~((~0)<<(bitsToWriteThisRound-bitsInBuffer));
        	}
            if (DBG) System.out.println("buf2=" + toBinary(buf2));  //TODO
        	
        	trg[ptA] &= eraseMask;  //TODO can we just assign buf2 here????
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO
        	
        	buf2 &= UNIT_0xFF; //TODO cut of heading bits??? Why?
            if (DBG) System.out.println("buf2=" + toBinary(buf2));  //TODO

         	startBitT = UNIT_BITS;
            trg[ptA] |= buf2;
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO
            
            //from now on, always delete everything
            eraseMask = 0;
            bitsWritten += bitsToWriteThisRound;
            bitsInBuffer -= bitsToWriteThisRound;
            //from now on, always write 8
            bitsToWriteThisRound = UNIT_BITS;
            
    		psA++;
    		ptA++;
    		
    		if (bitsToCopy-bitsWritten <= UNIT_BITS) {
    			writingFinished = true;
    		}
    	}

    	//write remaining bits - this should be less than 8.
    	if (bitsWritten < bitsToCopy) {
            //erase byte[] first - create mask
            int bitsToWrite = bitsToCopy-bitsWritten;
            if (DBG) System.out.println("em=" + toBinary(eraseMask));  //TODO
            if (bitsWritten == 0) {
            	//start and end in same target byte
            	eraseMask = (UNIT_0xFF >>> bitsToWrite) | UNIT_0xFF00;
            	//we are in the first byte, so writing may not start at the left side
            	eraseMask >>>= (UNIT_BITS-startBitT);
            if (DBG) System.out.println("em=" + toBinary(eraseMask));  //TODO
        		buf <<= (startBitT-bitsToWrite);
                if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
            } else {
                eraseMask = (UNIT_0xFF >>> bitsToWrite);
        		buf <<= (UNIT_BITS-bitsToWrite);
                if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
            }
            //erase bits
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO
            trg[ptA] &= eraseMask;
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO

    		trg[ptA] |= buf;
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO
    	}
    }
    
    public static void copyBitsRight(short[] src, int posSrc, short[] trg, int posTrg, int len) {
    	if (len==0) {
    		return;
    	}
    	final boolean DBG = false; //TODO
    	if (posSrc < 0 || posTrg < 0) {
    		throw new IllegalArgumentException("s=" + posSrc + " t=" + posTrg);
    	}
    	if (posSrc + len > src.length*UNIT_BITS || posTrg + len > trg.length*UNIT_BITS) {
    		throw new IllegalArgumentException("s=" + posSrc + " t=" + posTrg + " len=" + len);
    	}
    	long buf = 0;
//        int psA = posSrc >>> UNIT_3;
        int startBitS = UNIT_BITS - (posSrc & UNIT_0x07); //counting from right to left (low to high) [8..1]
        int startBitT_lr = (posTrg & UNIT_0x07); //counting from left to right, [0..7];
        int startBitT = UNIT_BITS - (posTrg & UNIT_0x07); //counting from right to left (low to high) [8..1]
    	
        int bitsInBuffer = 0;
        final int bitsToCopy = len;
        int bitsRead = 0;
        int bitsWritten = 0;
        
        int psA = (posSrc+len-1) >>> UNIT_3;  //last bit to be read
        int ptA = (posTrg+len-1) >>> UNIT_3;  //last bit to be written
        int endBitS = ((posSrc+len-1) & UNIT_0x07);   //last bit to be read
        int endBitT = ((posTrg+len-1) & UNIT_0x07);   //last bit to be written
        if (endBitS != UNIT_BITS-1) {
        	if (endBitS+1 - bitsToCopy >= 0) {
        		//just a few bits to move within a single byte
        		buf = src[psA] & UNIT_0xFF;
            	//start and end in same target byte
        		long eraseMask = (UNIT_0xFF >>> len) | UNIT_0xFF00;
            	//we are in the first byte, so writing may not start at the left side
            	eraseMask >>>= (endBitT+1-len);
        		buf >>>= endBitT-endBitS;
        		buf &= ~eraseMask;
        		trg[ptA] &= eraseMask;
        		trg[ptA] |= buf;
        		return; //?
        	} else {
        		
        	}
        }
        if (true) throw new RuntimeException();
        
        
        
    	//read bits of half-used byte into buffer
    	if (startBitS != UNIT_BITS) {
            long mask = (1L << startBitS)-1L;
            buf |= src[psA] & mask;
            if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
            bitsInBuffer = startBitS;
            bitsRead = startBitS;
            psA++;
            if (bitsRead > bitsToCopy) {
            	buf >>>= (bitsRead - bitsToCopy);
            	bitsRead = bitsToCopy;
            	bitsInBuffer = bitsToCopy;
            }
    	}
    	
    	//erase-mask for setting target-bits to 0 (necessary for overwriting via OR/|=)
        long eraseMask = (1L << startBitT) - 1L;
        eraseMask = ~eraseMask;  // 00 for all bit that need overwriting.
        if (DBG) System.out.println("em=" + toBinary(eraseMask));  //TODO
        int bitsToWriteThisRound = startBitT < len ? startBitT : len;
    	
    	//main loop - traverses everything but the last byte
        boolean readingFinished = false;
        boolean writingFinished = false;
        while (!(readingFinished && writingFinished) ) {
    	//while (bitsWritten <= bitsToCopy && !readingFinished) {
    		//read into buffer
        	if (bitsRead < bitsToCopy) {
	    		buf <<= UNIT_BITS;
	            if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
	            if (DBG) System.out.println("src=" + toBinary(src[psA]));  //TODO
	    		buf |= src[psA] & UNIT_0xFF; //Otherwise leading bits may be 111111111
	    		if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
	    		bitsRead += UNIT_BITS;
	    		bitsInBuffer += UNIT_BITS;
	            if (bitsRead >= bitsToCopy) {
	            	readingFinished = true;
	            	if (bitsRead > bitsToCopy) {
		            	int d = bitsRead - bitsToCopy;
		            	buf >>>= d;
	        			if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
		            	bitsRead -= d;
		            	bitsInBuffer -= d;
	            	}
	            }
        	} else {
        		readingFinished = true;
        	}
    		
    		
    		//write
           	//Only write, if last written bit is last bit of current byte. ->End-aligned.
        	if (startBitT_lr + bitsInBuffer < UNIT_BITS) {
        		break;
        	}
        	
        	long buf2 = buf;
            if (DBG) System.out.println("buf2=" + toBinary(buf));  //TODO

            buf2 >>>= bitsInBuffer-bitsToWriteThisRound; 
            if (DBG) System.out.println("buf2=" + toBinary(buf2));  //TODO
        	
        	trg[ptA] &= eraseMask;  //TODO can we just assign buf2 here????
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO
        	
        	buf2 &= UNIT_0xFF; //TODO cut of heading bits??? Why?
            if (DBG) System.out.println("buf2=" + toBinary(buf2));  //TODO

         	startBitT = UNIT_BITS;
            trg[ptA] |= buf2;
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO
            
            //from now on, always delete everything
            eraseMask = 0;
            bitsWritten += bitsToWriteThisRound;
            bitsInBuffer -= bitsToWriteThisRound;
            //from now on, always write 8
            bitsToWriteThisRound = UNIT_BITS;
            
    		psA++;
    		ptA++;
    		
    		if (bitsToCopy-bitsWritten <= UNIT_BITS) {
    			writingFinished = true;
    		}
    	}

    	//write remaining bits - this should be less than 8.
    	if (bitsWritten < bitsToCopy) {
            //erase byte[] first - create mask
            int bitsToWrite = bitsToCopy-bitsWritten;
            if (DBG) System.out.println("em=" + toBinary(eraseMask));  //TODO
            if (bitsWritten == 0) {
            	//start and end in same target byte
            	eraseMask = (UNIT_0xFF >>> bitsToWrite) | UNIT_0xFF00;
            	//we are in the first byte, so writing may not start at the left side
            	eraseMask >>>= (UNIT_BITS-startBitT);
            if (DBG) System.out.println("em=" + toBinary(eraseMask));  //TODO
        		buf <<= (startBitT-bitsToWrite);
                if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
            } else {
                eraseMask = (UNIT_0xFF >>> bitsToWrite);
        		buf <<= (UNIT_BITS-bitsToWrite);
                if (DBG) System.out.println("buf=" + toBinary(buf));  //TODO
            }
            //erase bits
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO
            trg[ptA] &= eraseMask;
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO

    		trg[ptA] |= buf;
            if (DBG) System.out.println("trg=" + toBinary(trg));  //TODO
    	}
    }
    
	//TODO this could be much faster by using a LONG (INT?) which is filled with source bytes
	//and then accordingly shifted and assigned to target bytes.
	/**
	 * @param ba byte array
	 * @param posBit Counts from left to right!!!
	 * @return current bit
	 */
    public static boolean getBit(short[] ba, int posBit) {
        int pA = posBit >>> UNIT_3;
        //last three bit [0..7]
        posBit &= UNIT_0x07;
        return (ba[pA] & (1L << (UNIT_BITS-1-posBit))) != 0;
	}

    public static void setBit(short[] ba, int posBit, boolean b) {
        int pA = posBit >>> UNIT_3;
        //last three bit [0..7]
        posBit &= UNIT_0x07;
        if (b) {
            ba[pA] |= (1L << (UNIT_BITS-1-posBit));
        } else {
            ba[pA] &= (~(1L << (UNIT_BITS-1-posBit)));
        }
	}

    
    /**
     * This one 
     * 
     * @param ba		byte[]
     * @param startBit	start bit
     * @param nValues	number of values
     * @param val		value to search for
     * @param valWidth	bit width of the values
     * @return			index of value or according negative index if value was not found
     */
    public static int binarySearch(short[] ba, int startBit, int nValues, int val, int valWidth) {
    	int min = 0;
    	int max = nValues - 1;

    	while (min <= max) {
    		int mid = (min + max) >>> 1;
            long midVal = readArray(ba, mid*valWidth+startBit, valWidth);

            if (midVal < val) {
            	min = mid + 1;
            } else if (midVal > val) {
            	max = mid - 1;
            } else {
            	return mid; // key found
            }
    	}
    	return -(min + 1);  // key not found.
    }
    
    /**
     * Calculate array size for given number of bits.
     * This takes into account JVM memory management, which allocates multiples of 8 bytes.
     * @param nBits number of bits
     * @return array size.
     */
    public static int calcArraySize(int nBits) {
      int arraySize = (nBits)>>>3; // to bytes
      arraySize = (arraySize)>>>3; // align 8 bytes
      if (arraySize*8*8 < nBits) {
          arraySize++;
      }
      //turn it into bytes
      arraySize <<= 3;      
      //now we need to turn the required bytes into the array's unit
      arraySize = arraySize>>> (UNIT_3-3);
    	
      //old version: just calculates required size
//        int arraySize = (nBits)>>>Bits.UNIT_3;
//        if (arraySize*Bits.UNIT_BITS < nBits) {
//            arraySize++;
//        }
        return arraySize;
    }

    /**
     * Resize an array.
     * @param oldA old array
     * @param newSizeBits number of bits
     * @return New array larger array.
     */
    public static short[] arrayExpand(short[] oldA, int newSizeBits) {
    	short[] newA = new short[calcArraySize(newSizeBits)];
    	System.arraycopy(oldA, 0, newA, 0, oldA.length);
    	statAExpand++;
    	return newA;
    }
    
    public static short[] arrayCreate(int nBits) {
    	short[] newA = new short[calcArraySize(nBits)];
    	statACreate++;
    	return newA;
    }
    
    /**
     * Ensure capacity of an array. Expands the array if required.
     * @param oldA old array
     * @param requiredBits number of bits
     * @return Same array or expanded array.
     */
    public static short[] arrayEnsureSize(short[] oldA, int requiredBits) {
    	if (isCapacitySufficient(oldA, requiredBits)) {
    		return oldA;
    	}
    	return arrayExpand(oldA, requiredBits);
    }
    
    public static boolean isCapacitySufficient(short[] a, int requiredBits) {
    	return (a.length*UNIT_BITS >= requiredBits);
    }
    
    public static short[] arrayTrim(short[] oldA, int requiredBits) {
    	int reqSize = calcArraySize(requiredBits);
    	if (oldA.length == reqSize) {
    		return oldA;
    	} else if (oldA.length>>= 1;
        }
        return sb.toString();
    }

	public static String toBinary(long[] la, int DEPTH) {
	    StringBuilder sb = new StringBuilder();
	    for (long l: la) {
	    	sb.append(toBinary(l, DEPTH));
	        sb.append(", ");
	    }
	    return sb.toString();
	}

    public static String toBinary(short[] ba) {
        StringBuilder sb = new StringBuilder();
        for (short l: ba) {
        	sb.append(toBinary(l, UNIT_BITS));
            sb.append(", ");
        }
        return sb.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy