github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/runtime/bytearray.go (about) 1 // Copyright 2017 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package grumpy 16 17 import ( 18 "bytes" 19 "fmt" 20 "reflect" 21 "sync" 22 ) 23 24 var ( 25 // ByteArrayType is the object representing the Python 'bytearray' type. 26 ByteArrayType = newBasisType("bytearray", reflect.TypeOf(ByteArray{}), toByteArrayUnsafe, ObjectType) 27 ) 28 29 // ByteArray represents Python 'bytearray' objects. 30 type ByteArray struct { 31 Object 32 mutex sync.RWMutex 33 value []byte 34 } 35 36 func toByteArrayUnsafe(o *Object) *ByteArray { 37 return (*ByteArray)(o.toPointer()) 38 } 39 40 // ToObject upcasts a to an Object. 41 func (a *ByteArray) ToObject() *Object { 42 return &a.Object 43 } 44 45 // Value returns the underlying bytes held by a. 46 func (a *ByteArray) Value() []byte { 47 return a.value 48 } 49 50 func byteArrayEq(f *Frame, v, w *Object) (*Object, *BaseException) { 51 return byteArrayCompare(v, w, False, True, False), nil 52 } 53 54 func byteArrayGE(f *Frame, v, w *Object) (*Object, *BaseException) { 55 return byteArrayCompare(v, w, False, True, True), nil 56 } 57 58 func byteArrayGetItem(f *Frame, o, key *Object) (result *Object, raised *BaseException) { 59 a := toByteArrayUnsafe(o) 60 if key.typ.slots.Index != nil { 61 index, raised := IndexInt(f, key) 62 if raised != nil { 63 return nil, raised 64 } 65 a.mutex.RLock() 66 elems := a.Value() 67 if index, raised = seqCheckedIndex(f, len(elems), index); raised == nil { 68 result = NewInt(int(elems[index])).ToObject() 69 } 70 a.mutex.RUnlock() 71 return result, raised 72 } 73 if key.isInstance(SliceType) { 74 a.mutex.RLock() 75 elems := a.Value() 76 start, stop, step, sliceLen, raised := toSliceUnsafe(key).calcSlice(f, len(elems)) 77 if raised == nil { 78 value := make([]byte, sliceLen) 79 if step == 1 { 80 copy(value, elems[start:stop]) 81 } else { 82 i := 0 83 for j := start; j != stop; j += step { 84 value[i] = elems[j] 85 i++ 86 } 87 } 88 result = (&ByteArray{Object: Object{typ: ByteArrayType}, value: value}).ToObject() 89 } 90 a.mutex.RUnlock() 91 return result, raised 92 } 93 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("bytearray indices must be integers or slice, not %s", key.typ.Name())) 94 } 95 96 func byteArrayGT(f *Frame, v, w *Object) (*Object, *BaseException) { 97 return byteArrayCompare(v, w, False, False, True), nil 98 } 99 100 func byteArrayInit(f *Frame, o *Object, args Args, _ KWArgs) (*Object, *BaseException) { 101 if raised := checkFunctionArgs(f, "__init__", args, IntType); raised != nil { 102 return nil, raised 103 } 104 a := toByteArrayUnsafe(o) 105 a.mutex.Lock() 106 a.value = make([]byte, toIntUnsafe(args[0]).Value()) 107 a.mutex.Unlock() 108 return None, nil 109 } 110 111 func byteArrayLE(f *Frame, v, w *Object) (*Object, *BaseException) { 112 return byteArrayCompare(v, w, True, True, False), nil 113 } 114 115 func byteArrayLT(f *Frame, v, w *Object) (*Object, *BaseException) { 116 return byteArrayCompare(v, w, True, False, False), nil 117 } 118 119 func byteArrayNative(f *Frame, o *Object) (reflect.Value, *BaseException) { 120 a := toByteArrayUnsafe(o) 121 a.mutex.RLock() 122 result := reflect.ValueOf(a.Value()) 123 a.mutex.RUnlock() 124 return result, nil 125 } 126 127 func byteArrayNE(f *Frame, v, w *Object) (*Object, *BaseException) { 128 return byteArrayCompare(v, w, True, False, True), nil 129 } 130 131 func byteArrayRepr(f *Frame, o *Object) (*Object, *BaseException) { 132 a := toByteArrayUnsafe(o) 133 a.mutex.RLock() 134 s, raised := Repr(f, NewStr(string(a.Value())).ToObject()) 135 a.mutex.RUnlock() 136 if raised != nil { 137 return nil, raised 138 } 139 return NewStr(fmt.Sprintf("bytearray(b%s)", s.Value())).ToObject(), nil 140 } 141 142 func byteArrayStr(f *Frame, o *Object) (*Object, *BaseException) { 143 a := toByteArrayUnsafe(o) 144 a.mutex.RLock() 145 s := string(a.Value()) 146 a.mutex.RUnlock() 147 return NewStr(s).ToObject(), nil 148 } 149 150 func initByteArrayType(dict map[string]*Object) { 151 ByteArrayType.slots.Eq = &binaryOpSlot{byteArrayEq} 152 ByteArrayType.slots.GE = &binaryOpSlot{byteArrayGE} 153 ByteArrayType.slots.GetItem = &binaryOpSlot{byteArrayGetItem} 154 ByteArrayType.slots.GT = &binaryOpSlot{byteArrayGT} 155 ByteArrayType.slots.Init = &initSlot{byteArrayInit} 156 ByteArrayType.slots.LE = &binaryOpSlot{byteArrayLE} 157 ByteArrayType.slots.LT = &binaryOpSlot{byteArrayLT} 158 ByteArrayType.slots.Native = &nativeSlot{byteArrayNative} 159 ByteArrayType.slots.NE = &binaryOpSlot{byteArrayNE} 160 ByteArrayType.slots.Repr = &unaryOpSlot{byteArrayRepr} 161 ByteArrayType.slots.Str = &unaryOpSlot{byteArrayStr} 162 } 163 164 func byteArrayCompare(v, w *Object, ltResult, eqResult, gtResult *Int) *Object { 165 if v == w { 166 return eqResult.ToObject() 167 } 168 // For simplicity we make a copy of w if it's a str or bytearray. This 169 // is inefficient and it may be useful to optimize. 170 var data []byte 171 switch { 172 case w.isInstance(StrType): 173 data = []byte(toStrUnsafe(w).Value()) 174 case w.isInstance(ByteArrayType): 175 a := toByteArrayUnsafe(w) 176 a.mutex.RLock() 177 data = make([]byte, len(a.value)) 178 copy(data, a.value) 179 a.mutex.RUnlock() 180 default: 181 return NotImplemented 182 } 183 a := toByteArrayUnsafe(v) 184 a.mutex.RLock() 185 cmp := bytes.Compare(a.value, data) 186 a.mutex.RUnlock() 187 switch cmp { 188 case -1: 189 return ltResult.ToObject() 190 case 0: 191 return eqResult.ToObject() 192 default: 193 return gtResult.ToObject() 194 } 195 }