github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/aeron/flyweight/fields.go (about) 1 /* 2 Copyright 2016-2018 Stanislav Liberman 3 Copyright 2022 Steven Stern 4 5 Licensed under the Apache License, Version 2.0 (the "License"); 6 you may not use this file except in compliance with the License. 7 You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11 Unless required by applicable law or agreed to in writing, software 12 distributed under the License is distributed on an "AS IS" BASIS, 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 See the License for the specific language governing permissions and 15 limitations under the License. 16 */ 17 18 package flyweight 19 20 import ( 21 syncatomic "sync/atomic" 22 "unsafe" 23 24 "github.com/lirm/aeron-go/aeron/atomic" 25 "github.com/lirm/aeron-go/aeron/util" 26 ) 27 28 // Field is the interface for a field in a flyweight wrapper. It expects a preallocated buffer and offset into it, as 29 // arguments. 30 type Field interface { 31 Wrap(buffer *atomic.Buffer, offset int) 32 Get() interface{} 33 } 34 35 // Int32Field is int32 field for flyweight 36 type Int32Field struct { 37 offset unsafe.Pointer 38 } 39 40 func (fld *Int32Field) Wrap(buffer *atomic.Buffer, offset int) int { 41 atomic.BoundsCheck(int32(offset), 4, buffer.Capacity()) 42 43 fld.offset = unsafe.Pointer(uintptr(buffer.Ptr()) + uintptr(offset)) 44 return 4 45 } 46 47 func (fld *Int32Field) Get() int32 { 48 return *(*int32)(fld.offset) 49 } 50 51 func (fld *Int32Field) Set(value int32) { 52 *(*int32)(fld.offset) = value 53 } 54 55 func (fld *Int32Field) CAS(curValue, newValue int32) bool { 56 n := syncatomic.CompareAndSwapInt32((*int32)(fld.offset), curValue, newValue) 57 return n 58 } 59 60 // Int64Field is int64 field for flyweight 61 type Int64Field struct { 62 offset unsafe.Pointer 63 } 64 65 func (fld *Int64Field) Wrap(buffer *atomic.Buffer, offset int) int { 66 atomic.BoundsCheck(int32(offset), 8, buffer.Capacity()) 67 68 fld.offset = unsafe.Pointer(uintptr(buffer.Ptr()) + uintptr(offset)) 69 return 8 70 } 71 72 func (fld *Int64Field) Get() int64 { 73 return *(*int64)(fld.offset) 74 } 75 76 func (fld *Int64Field) Set(value int64) { 77 *(*int64)(fld.offset) = value 78 } 79 80 func (fld *Int64Field) GetAndAddInt64(value int64) int64 { 81 n := syncatomic.AddInt64((*int64)(fld.offset), value) 82 return n - value 83 } 84 85 func (fld *Int64Field) CAS(curValue, newValue int64) bool { 86 n := syncatomic.CompareAndSwapInt64((*int64)(fld.offset), curValue, newValue) 87 return n 88 } 89 90 // StringField is string field for flyweight 91 type StringField struct { 92 lenOffset unsafe.Pointer 93 dataOffset unsafe.Pointer 94 fly Flyweight 95 } 96 97 func (fld *StringField) Wrap(buffer *atomic.Buffer, offset int, fly Flyweight, align bool) int { 98 99 off := int32(offset) 100 offsetAdjustment := 0 101 if align { 102 off = util.AlignInt32(int32(offset), 4) 103 offsetAdjustment = int(off) - offset 104 } 105 106 atomic.BoundsCheck(off, 4, buffer.Capacity()) 107 108 fld.lenOffset = unsafe.Pointer(uintptr(buffer.Ptr()) + uintptr(off)) 109 l := *(*int32)(fld.lenOffset) 110 111 atomic.BoundsCheck(off+4, l, buffer.Capacity()) 112 113 fld.fly = fly 114 fld.dataOffset = unsafe.Pointer(uintptr(buffer.Ptr()) + uintptr(off+4)) 115 return 4 + int(l) + offsetAdjustment 116 } 117 118 func (fld *StringField) Get() string { 119 length := *(*int32)(fld.lenOffset) 120 121 bArr := make([]byte, length) 122 for ix := 0; ix < int(length); ix++ { 123 uptr := unsafe.Pointer(uintptr(fld.dataOffset) + uintptr(ix)) 124 bArr[ix] = *(*uint8)(uptr) 125 } 126 127 return string(bArr) 128 } 129 130 func (fld *StringField) Set(value string) { 131 length := int32(len(value)) 132 prevLen := *(*int32)(fld.lenOffset) 133 *(*int32)(fld.lenOffset) = length 134 135 bArr := []byte(value) 136 srcUptr := unsafe.Pointer(&bArr[0]) 137 138 util.Memcpy(uintptr(fld.dataOffset), uintptr(srcUptr), length) 139 140 size := fld.fly.Size() 141 size -= int(prevLen) 142 size += int(length) 143 fld.fly.SetSize(size) 144 } 145 146 type RawDataField struct { 147 buf atomic.Buffer 148 } 149 150 func (f *RawDataField) Wrap(buffer *atomic.Buffer, offset int, length int32) int { 151 ptr := uintptr(buffer.Ptr()) + uintptr(offset) 152 f.buf.Wrap(unsafe.Pointer(ptr), length) 153 154 return int(length) 155 } 156 157 func (f *RawDataField) Get() *atomic.Buffer { 158 return &f.buf 159 } 160 161 type Padding struct { 162 raw RawDataField 163 } 164 165 // Wrap for padding takes size to pass this particular position to. That size will be rounded down to match alignment. 166 func (f *Padding) Wrap(buffer *atomic.Buffer, offset int, size int32, alignment int32) int { 167 maxLength := int32(offset) + size 168 newLen := maxLength - maxLength%alignment - int32(offset) 169 if newLen < 0 { 170 newLen += alignment 171 } 172 173 return f.raw.Wrap(buffer, offset, newLen) 174 } 175 176 func (f *Padding) Get() *atomic.Buffer { 177 return f.raw.Get() 178 } 179 180 type LengthAndRawDataField struct { 181 lenOffset unsafe.Pointer 182 buf atomic.Buffer 183 } 184 185 func (fld *LengthAndRawDataField) Length() int32 { 186 return *(*int32)(fld.lenOffset) 187 } 188 189 func (fld *LengthAndRawDataField) SetLength(length int32) { 190 *(*int32)(fld.lenOffset) = length 191 } 192 193 func (fld *LengthAndRawDataField) Wrap(buffer *atomic.Buffer, rawOffset int) int { 194 offset := util.AlignInt32(int32(rawOffset), 4) 195 offsetAdjustment := int(offset) - rawOffset 196 197 atomic.BoundsCheck(offset, 4, buffer.Capacity()) 198 fld.lenOffset = unsafe.Pointer(uintptr(buffer.Ptr()) + uintptr(offset)) 199 200 atomic.BoundsCheck(offset+4, fld.Length(), buffer.Capacity()) 201 ptr := uintptr(buffer.Ptr()) + uintptr(offset+4) 202 fld.buf.Wrap(unsafe.Pointer(ptr), buffer.Capacity()-offset) 203 204 return 4 + int(fld.Length()) + offsetAdjustment 205 } 206 207 func (fld *LengthAndRawDataField) CopyBuffer(buffer *atomic.Buffer, offset int32, length int32) { 208 fld.SetLength(length) 209 fld.buf.PutBytes(0, buffer, offset, length) 210 } 211 212 func (fld *LengthAndRawDataField) CopyString(data string) { 213 fld.SetLength(int32(len(data))) 214 bArr := []byte(data) 215 fld.buf.PutBytesArray(0, &bArr, 0, int32(len(data))) 216 } 217 218 func (fld *LengthAndRawDataField) GetAsBuffer() *atomic.Buffer { 219 return &fld.buf 220 } 221 222 func (fld *LengthAndRawDataField) GetAsASCII() string { 223 bArr := make([]byte, fld.Length()) 224 fld.buf.GetBytes(0, bArr) 225 return string(bArr) 226 }