/* Copyright 2010 Aaron J. Radke 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 cc.drx trait Unsigned extends Any{ //---required def depth:Int def toLong:Long //--optimizable def mask:Long = depth.iterate(0L){_ << 1 | 1} def signed:Long = {val shift = 64 - depth; toLong << shift >> shift} //move sign bit up then pull it back down if it is signed def hex = s"0x%0${depth/4}x" format toLong override def toString = hex } trait UnsignedObject{ // def depth:Int /* //TODO make better byte compositions to avoid java 2's complement integer assumptions oddities type US = Iterable[Unsigned] trait Pack[A] { def pack(xs:US):A } object Pack{ def packLong(us:US):Long = us.toList.reverse.foldLeft( (0,0L) ){case ((d,v), u) => (d + u.depth, u.toLong << d) }._2 implicit object PackInt extends Pack[Int]{ def pack(xs:US):Int = packLong(xs).toInt} implicit object PackLong extends Pack[Long]{ def pack(xs:US):Long = packLong(xs) } implicit object PackByte extends Pack[Byte]{ def pack(xs:US):Byte = packLong(xs).toByte } } def pack[A](us:US)(implicit packer:Pack[A]):A = packer.pack(us) */ } //TODO add assertions bounds for the constructions: i.e. Ints should not be bigger than an Byte if an unsigned byte is constructed //the following classes make using unsigned integer types more first class object U4 extends UnsignedObject{ val MinValue = U4(0x0) val MaxValue = U4(0xF) val byteWidth = 1 // 4bits // val bound = Bound(MinValue,MaxValue) @inline final def apply(v:Int):U4 = new U4((v & 0xF).toByte) @inline final def apply(v:Byte):U4 = new U4((v & 0xF).toByte) //warning: bytes could be lost here // def fromByteArray(bytes:Array[Bytes],offset:Int=0):U4 = new U4( bytes(offset) ) } object U8{ val MinValue = U8(0x00) val MaxValue = U8(0xFF) val byteWidth = 1 // 8bits // val bound = Bound(MinValue,MaxValue) @inline final def apply(v:Byte):U8 = new U8(v) @inline final def apply(v:Int):U8 = new U8(v.toByte) //TODO maybe make these over determined constructors unsafe? @inline final def apply(h:U4,l:U4):U8 = new U8( ( h.toInt<<4 | l.toInt).toByte ) def fromByteArray(bytes:Array[Byte],offset:Int=0):U4 = U4(bytes(offset)) } object U12{ val MinValue = U12(0x000) val MaxValue = U12(0xFFF) val byteWidth = 2 // val bound = Bound(MinValue,MaxValue) @inline final def apply(v:Short):U12 = new U12((v & 0x0FFF).toShort) @inline final def apply(v:Int):U12 = new U12((v & 0x0FFF).toShort) @inline final def apply(hh:U4, h:U4,l:U4):U12 = new U12( ((hh.toInt << 8 | h.toInt<<4 | l.toInt)&0x0FFF).toShort ) } object U16{ val MinValue = U16(0x0000) val MaxValue = U16(0xFFFF) val byteWidth = 2 // val bound = Bound(MinValue,MaxValue) @inline final def apply(v:Short):U16 = new U16(v) @inline final def apply(v:Int):U16 = new U16(v.toShort) @inline final def apply(h:U8,l:U8):U16 = new U16( (h.toInt<<8 | l.toInt ).toShort ) @inline final def apply(a:U4,b:U4,c:U4,d:U4):U16 = new U16(( a.toInt<<12 | b.toInt<<8 | c.toInt<<4 | d.toInt).toShort) } object U24{ val MinValue = U24(0x00000000) val MaxValue = U24(0x00FFFFFF) // val bound = Bound(MinValue,MaxValue) @inline final def apply(v:Int):U24 = new U24((v & 0x00FFFFFF).toInt) val byteWidth = 3 } /**Int constructor*/ object U32{ val MinValue = U32(0x00000000L) val MaxValue = U32(0xFFFFFFFFL) val byteWidth = 4 // val bound = Bound(MinValue,MaxValue) @inline final def apply(v:Int):U32 = new U32(v) @inline final def apply(v:Long):U32 = new U32((v & 0xFFFFFFFFL).toInt) @inline final def apply(h:U16,l:U16):U32 = new U32( h.toInt<<16 | l.toInt ) @inline final def apply(a:U8,b:U8,c:U8,d:U8):U32 = new U32(( a.toInt<<24 | b.toInt<<16 | c.toInt<<8 | d.toInt).toShort) def fromByteArray(bytes:Array[Byte],offset:Int=0):U32 = { @inline def b(i:Int):U8 = U8(bytes(i+offset)) U32(b(0), b(1), b(2), b(3)) } } /**Long constructor*/ object U64{ val MinValue = U64(0x0L) val MaxValue = U64(0xFFFFFFFFFFFFFFFFL) val byteWidth = 8 // val bound = Bound(MinValue,MaxValue) @inline final def apply(v:Long):U64 = new U64(v) @inline final def apply(h:U32,l:U32):U64 = new U64( h.toLong<<32 | l.toLong) } //--classes /**Nibble wrapper*/ class U4(val value:Byte) extends AnyVal with Unsigned{ def depth:Int = 4 def toByte = value def toShort = toInt.toShort def toInt = value & 0xF def toLong = value & 0xFL def +(that:U4):U4 = U4(this.value + that.value) } /**Byte wrapper*/ class U8(val value:Byte) extends AnyVal with Unsigned{ def depth:Int = 8 def toShort = toInt.toShort def toInt = value & 0xFF def toLong = value & 0xFFL def hi:U4 = U4(value >> 4) def lo:U4 = U4(value) def +(that:U8):U8 = U8(this.value + that.value) } class U12(val value:Short) extends AnyVal with Unsigned{ def depth:Int = 12 def toShort = value def toInt = value & 0x0FFF def toLong = value & 0x0FFFL def +(that:U12):U12 = U12(this.value + that.value) //TODO optimize so no masking is required } /**Short wrapper*/ class U16(val value:Short) extends AnyVal with Unsigned{ def depth:Int = 16 def toChar = value.toChar def toInt = value & 0xFFFF def toLong = value & 0xFFFFL def hi:Byte = (value >> 8).toByte def lo:Byte = value.toByte def +(that:U16):U16 = U16(this.value + that.value) } class U24(val value:Int) extends AnyVal with Unsigned{ def depth:Int = 24 def toInt = value & 0x00FFFFFF def toLong = value & 0x00FFFFFFL def +(that:U24):U24 = U24(this.value + that.value) //TODO optimize } /**Int wrapper*/ class U32(val value:Int) extends AnyVal with Unsigned{ def depth:Int = 32 //toInt is not safe here because the value could be negative def toLong = value & 0xFFFFFFFFL def hi:Short = (value >> 16).toShort def lo:Short = value.toShort def +(that:U32):U32 = U32(this.value + that.value) // def toByteArray:Array[Byte] = { //--implicit from DrxInt // @inline def b(shift:Int):Byte = ((value >> shift) & 0xFF).toByte // Array( b(24), b(16), b(8), b(0) ) // } } /**Long wrapper*/ class U64(val value:Long) extends AnyVal with Unsigned{ def depth:Int = 64 def toLong = value def hi:Int = (value >> 32).toInt def lo:Int = value.toInt def +(that:U64):U64 = U64(this.value + that.value) }