github.com/scottcagno/storage@v1.8.0/pkg/mmap/segment/segment.go (about) 1 package segment 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math" 7 "reflect" 8 "unsafe" 9 ) 10 11 var ( 12 ErrBadValue = fmt.Errorf("segment: bad value") 13 ErrOutOfBounds = fmt.Errorf("segment: out of bounds") 14 Fault = fmt.Errorf("segmentation fault") 15 ) 16 17 // MaxUintptr is the maximum platform dependent unsigned integer 18 // large enough to store the uninterpreted bits of a pointer value. 19 const MaxUintptr = ^uintptr(0) 20 21 // Sizes of types in bytes. 22 const ( 23 Int8Size = 1 24 Int16Size = 2 25 Int32Size = 4 26 Int64Size = 8 27 Uint8Size = 1 28 Uint16Size = 2 29 Uint32Size = 4 30 Uint64Size = 8 31 Float32Size = 4 32 Float64Size = 8 33 Complex64Size = 8 34 Complex128Size = 16 35 ) 36 37 // Segment is a data segment. 38 // See https://golang.org/ref/spec#Numeric_types for details. 39 type Segment struct { 40 // offset specifies the offset of this segment. 41 offset int64 42 // data specifies the descriptor of the raw byte data associated with this segment. 43 // TODO: Choose the correct type for this field and it's initialization mechanism. 44 data reflect.SliceHeader 45 } 46 47 // New returns a new data segment. 48 func New(offset int64, data []byte) *Segment { 49 return &Segment{ 50 offset: offset, 51 data: *(*reflect.SliceHeader)(unsafe.Pointer(&data)), 52 } 53 } 54 55 // Pointer returns an untyped pointer to the value from this segment or panics at the access violation. 56 func (seg *Segment) Pointer(offset int64, length uintptr) uintptr { 57 if offset < seg.offset || length > math.MaxInt64 { 58 panic(Fault) 59 } 60 offset -= seg.offset 61 if offset > math.MaxInt64-int64(length) || offset+int64(length) > int64(seg.data.Len) { 62 panic(Fault) 63 } 64 if uint64(offset) > uint64(MaxUintptr-seg.data.Data) { 65 panic(Fault) 66 } 67 return seg.data.Data + uintptr(offset) 68 } 69 70 // Int8 returns a pointer to the signed 8-bit integer from this segment or panics at the access violation. 71 func (seg *Segment) Int8(offset int64) *int8 { 72 return (*int8)(unsafe.Pointer(seg.Pointer(offset, Int8Size))) 73 } 74 75 // Int16 returns a pointer to the signed 16-bit integer from this segment or panics at the access violation. 76 func (seg *Segment) Int16(offset int64) *int16 { 77 return (*int16)(unsafe.Pointer(seg.Pointer(offset, Int16Size))) 78 } 79 80 // Int32 returns a pointer to the signed 32-bit integer from this segment or panics at the access violation. 81 func (seg *Segment) Int32(offset int64) *int32 { 82 return (*int32)(unsafe.Pointer(seg.Pointer(offset, Int32Size))) 83 } 84 85 // Int64 returns a pointer to the signed 64-bit integer from this segment or panics at the access violation. 86 func (seg *Segment) Int64(offset int64) *int64 { 87 return (*int64)(unsafe.Pointer(seg.Pointer(offset, Int64Size))) 88 } 89 90 // Uint8 returns a pointer to the unsigned 8-bit integer from this segment or panics at the access violation. 91 func (seg *Segment) Uint8(offset int64) *uint8 { 92 return (*uint8)(unsafe.Pointer(seg.Pointer(offset, Uint8Size))) 93 } 94 95 // Uint16 returns a pointer to the unsigned 16-bit integer from this segment or panics at the access violation. 96 func (seg *Segment) Uint16(offset int64) *uint16 { 97 return (*uint16)(unsafe.Pointer(seg.Pointer(offset, Uint16Size))) 98 } 99 100 // Uint32 returns a pointer to the unsigned 32-bit integer from this segment or panics at the access violation. 101 func (seg *Segment) Uint32(offset int64) *uint32 { 102 return (*uint32)(unsafe.Pointer(seg.Pointer(offset, Uint32Size))) 103 } 104 105 // Uint16 returns a pointer to the unsigned 64-bit integer from this segment or panics at the access violation. 106 func (seg *Segment) Uint64(offset int64) *uint64 { 107 return (*uint64)(unsafe.Pointer(seg.Pointer(offset, Uint64Size))) 108 } 109 110 // ScanUint sequentially reads the data into the unsigned integers pointed by v starting from the given offset. 111 func (seg *Segment) ScanUint(offset int64, v ...interface{}) error { 112 data := *(*[]byte)(unsafe.Pointer(&seg.data)) 113 if offset < seg.offset { 114 return ErrOutOfBounds 115 } 116 offset -= seg.offset 117 for _, val := range v { 118 switch value := val.(type) { 119 default: 120 return ErrBadValue 121 case *uint8: 122 if offset < 0 || offset > math.MaxInt64-Uint8Size || offset+Uint8Size > int64(len(data)) { 123 return ErrOutOfBounds 124 } 125 *value = data[offset:][0] 126 offset += Uint8Size 127 case *uint16: 128 if offset < 0 || offset > math.MaxInt64-Uint16Size || offset+Uint16Size > int64(len(data)) { 129 return ErrOutOfBounds 130 } 131 *value = binary.LittleEndian.Uint16(data[offset : offset+Uint16Size]) 132 offset += Uint16Size 133 case *uint32: 134 if offset < 0 || offset > math.MaxInt64-Uint32Size || offset+Uint32Size > int64(len(data)) { 135 return ErrOutOfBounds 136 } 137 *value = binary.LittleEndian.Uint32(data[offset : offset+Uint32Size]) 138 offset += Uint32Size 139 case *uint64: 140 if offset < 0 || offset > math.MaxInt64-Uint64Size || offset+Uint64Size > int64(len(data)) { 141 return ErrOutOfBounds 142 } 143 *value = binary.LittleEndian.Uint64(data[offset : offset+Uint64Size]) 144 offset += Uint64Size 145 } 146 } 147 return nil 148 } 149 150 // Float32 returns a pointer to the IEEE-754 32-bit floating-point number from this segment 151 // or panics at the access violation. 152 func (seg *Segment) Float32(offset int64) *float32 { 153 return (*float32)(unsafe.Pointer(seg.Pointer(offset, Float32Size))) 154 } 155 156 // Float64 returns a pointer to the IEEE-754 64-bit floating-point number from this segment 157 // or panics at the access violation. 158 func (seg *Segment) Float64(offset int64) *float64 { 159 return (*float64)(unsafe.Pointer(seg.Pointer(offset, Float64Size))) 160 } 161 162 // Complex64 returns a pointer to the complex number with float32 real and imaginary parts from this segment 163 // or panics at the access violation. 164 func (seg *Segment) Complex64(offset int64) *complex64 { 165 return (*complex64)(unsafe.Pointer(seg.Pointer(offset, Complex64Size))) 166 } 167 168 // Complex128 returns a pointer to the complex number with float64 real and imaginary parts from this segment 169 // or panics at the access violation. 170 func (seg *Segment) Complex128(offset int64) *complex128 { 171 return (*complex128)(unsafe.Pointer(seg.Pointer(offset, Complex128Size))) 172 }