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  }