Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
MIT No Attribution
Copyright 2023 Segment
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+67
View File
@@ -0,0 +1,67 @@
package base64
import (
"encoding/base64"
)
const (
StdPadding rune = base64.StdPadding
NoPadding rune = base64.NoPadding
encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
encodeIMAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"
letterRange = int8('Z' - 'A' + 1)
)
// StdEncoding is the standard base64 encoding, as defined in RFC 4648.
var StdEncoding = NewEncoding(encodeStd)
// URLEncoding is the alternate base64 encoding defined in RFC 4648.
// It is typically used in URLs and file names.
var URLEncoding = NewEncoding(encodeURL)
// RawStdEncoding is the standard unpadded base64 encoding defined in RFC 4648 section 3.2.
// This is the same as StdEncoding but omits padding characters.
var RawStdEncoding = StdEncoding.WithPadding(NoPadding)
// RawURLEncoding is the unpadded alternate base64 encoding defined in RFC 4648.
// This is the same as URLEncoding but omits padding characters.
var RawURLEncoding = URLEncoding.WithPadding(NoPadding)
// NewEncoding returns a new padded Encoding defined by the given alphabet,
// which must be a 64-byte string that does not contain the padding character
// or CR / LF ('\r', '\n'). Unlike the standard library, the encoding alphabet
// cannot be abitrary, and it must follow one of the know standard encoding
// variants.
//
// Required alphabet values:
// * [0,26): characters 'A'..'Z'
// * [26,52): characters 'a'..'z'
// * [52,62): characters '0'..'9'
// Flexible alphabet value options:
// * RFC 4648, RFC 1421, RFC 2045, RFC 2152, RFC 4880: '+' and '/'
// * RFC 4648 URI: '-' and '_'
// * RFC 3501: '+' and ','
//
// The resulting Encoding uses the default padding character ('='), which may
// be changed or disabled via WithPadding. The padding characters is urestricted,
// but it must be a character outside of the encoder alphabet.
func NewEncoding(encoder string) *Encoding {
if len(encoder) != 64 {
panic("encoding alphabet is not 64-bytes long")
}
if _, ok := allowedEncoding[encoder]; !ok {
panic("non-standard encoding alphabets are not supported")
}
return newEncoding(encoder)
}
var allowedEncoding = map[string]struct{}{
encodeStd: {},
encodeURL: {},
encodeIMAP: {},
}
+78
View File
@@ -0,0 +1,78 @@
//go:build amd64 && !purego
// +build amd64,!purego
package base64
import (
"encoding/base64"
"github.com/segmentio/asm/cpu"
"github.com/segmentio/asm/cpu/x86"
)
const (
encLutSize = 32
decLutSize = 48
minEncodeLen = 28
minDecodeLen = 45
)
func newEncoding(encoder string) *Encoding {
e := &Encoding{base: base64.NewEncoding(encoder)}
if cpu.X86.Has(x86.AVX2) {
e.enableEncodeAVX2(encoder)
e.enableDecodeAVX2(encoder)
}
return e
}
func (e *Encoding) enableEncodeAVX2(encoder string) {
// Translate values 0..63 to the Base64 alphabet. There are five sets:
//
// From To Add Index Example
// [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ
// [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz
// [52..61] [48..57] -4 [2..11] 0123456789
// [62] [43] -19 12 +
// [63] [47] -16 13 /
tab := [encLutSize]int8{int8(encoder[0]), int8(encoder[letterRange]) - letterRange}
for i, ch := range encoder[2*letterRange:] {
tab[2+i] = int8(ch) - 2*letterRange - int8(i)
}
e.enc = encodeAVX2
e.enclut = tab
}
func (e *Encoding) enableDecodeAVX2(encoder string) {
c62, c63 := int8(encoder[62]), int8(encoder[63])
url := c63 == '_'
if url {
c63 = '/'
}
// Translate values from the Base64 alphabet using five sets. Values outside
// of these ranges are considered invalid:
//
// From To Add Index Example
// [47] [63] +16 1 /
// [43] [62] +19 2 +
// [48..57] [52..61] +4 3 0123456789
// [65..90] [0..25] -65 4,5 ABCDEFGHIJKLMNOPQRSTUVWXYZ
// [97..122] [26..51] -71 6,7 abcdefghijklmnopqrstuvwxyz
tab := [decLutSize]int8{
0, 63 - c63, 62 - c62, 4, -65, -65, -71, -71,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x13, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B,
}
tab[(c62&15)+16] = 0x1A
tab[(c63&15)+16] = 0x1A
if url {
e.dec = decodeAVX2URI
} else {
e.dec = decodeAVX2
}
e.declut = tab
}
+42
View File
@@ -0,0 +1,42 @@
//go:build arm64 && !purego
// +build arm64,!purego
package base64
import (
"encoding/base64"
)
const (
encLutSize = 16
decLutSize = 2
minEncodeLen = 16 * 3
minDecodeLen = 8 * 4
)
func newEncoding(encoder string) *Encoding {
e := &Encoding{base: base64.NewEncoding(encoder)}
e.enableEncodeARM64(encoder)
e.enableDecodeARM64(encoder)
return e
}
func (e *Encoding) enableEncodeARM64(encoder string) {
c62, c63 := int8(encoder[62]), int8(encoder[63])
tab := [encLutSize]int8{
'a' - 26, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52,
'0' - 52, '0' - 52, '0' - 52, c62 - 62, c63 - 63, 'A', 0, 0,
}
e.enc = encodeARM64
e.enclut = tab
}
func (e *Encoding) enableDecodeARM64(encoder string) {
if encoder == encodeStd {
e.dec = decodeStdARM64
} else {
e.dec = decodeARM64
}
e.declut = [decLutSize]int8{int8(encoder[62]), int8(encoder[63])}
}
+94
View File
@@ -0,0 +1,94 @@
//go:build (amd64 || arm64) && !purego
// +build amd64 arm64
// +build !purego
package base64
import (
"encoding/base64"
"github.com/segmentio/asm/internal/unsafebytes"
)
// An Encoding is a radix 64 encoding/decoding scheme, defined by a
// 64-character alphabet.
type Encoding struct {
enc func(dst []byte, src []byte, lut *int8) (int, int)
enclut [encLutSize]int8
dec func(dst []byte, src []byte, lut *int8) (int, int)
declut [decLutSize]int8
base *base64.Encoding
}
// WithPadding creates a duplicate Encoding updated with a specified padding
// character, or NoPadding to disable padding. The padding character must not
// be contained in the encoding alphabet, must not be '\r' or '\n', and must
// be no greater than '\xFF'.
func (enc Encoding) WithPadding(padding rune) *Encoding {
enc.base = enc.base.WithPadding(padding)
return &enc
}
// Strict creates a duplicate encoding updated with strict decoding enabled.
// This requires that trailing padding bits are zero.
func (enc Encoding) Strict() *Encoding {
enc.base = enc.base.Strict()
return &enc
}
// Encode encodes src using the defined encoding alphabet.
// This will write EncodedLen(len(src)) bytes to dst.
func (enc *Encoding) Encode(dst, src []byte) {
if len(src) >= minEncodeLen && enc.enc != nil {
d, s := enc.enc(dst, src, &enc.enclut[0])
dst = dst[d:]
src = src[s:]
}
enc.base.Encode(dst, src)
}
// Encode encodes src using the encoding enc, writing
// EncodedLen(len(src)) bytes to dst.
func (enc *Encoding) EncodeToString(src []byte) string {
buf := make([]byte, enc.base.EncodedLen(len(src)))
enc.Encode(buf, src)
return string(buf)
}
// EncodedLen calculates the base64-encoded byte length for a message
// of length n.
func (enc *Encoding) EncodedLen(n int) int {
return enc.base.EncodedLen(n)
}
// Decode decodes src using the defined encoding alphabet.
// This will write DecodedLen(len(src)) bytes to dst and return the number of
// bytes written.
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
var d, s int
if len(src) >= minDecodeLen && enc.dec != nil {
d, s = enc.dec(dst, src, &enc.declut[0])
dst = dst[d:]
src = src[s:]
}
n, err = enc.base.Decode(dst, src)
n += d
return
}
// DecodeString decodes the base64 encoded string s, returns the decoded
// value as bytes.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
src := unsafebytes.BytesOf(s)
dst := make([]byte, enc.base.DecodedLen(len(s)))
n, err := enc.Decode(dst, src)
return dst[:n], err
}
// DecodedLen calculates the decoded byte length for a base64-encoded message
// of length n.
func (enc *Encoding) DecodedLen(n int) int {
return enc.base.DecodedLen(n)
}
+14
View File
@@ -0,0 +1,14 @@
//go:build purego || !(amd64 || arm64)
// +build purego !amd64,!arm64
package base64
import "encoding/base64"
// An Encoding is a radix 64 encoding/decoding scheme, defined by a
// 64-character alphabet.
type Encoding = base64.Encoding
func newEncoding(encoder string) *Encoding {
return base64.NewEncoding(encoder)
}
+9
View File
@@ -0,0 +1,9 @@
// Code generated by command: go run decode_asm.go -pkg base64 -out ../base64/decode_amd64.s -stubs ../base64/decode_amd64.go. DO NOT EDIT.
//go:build !purego
package base64
func decodeAVX2(dst []byte, src []byte, lut *int8) (int, int)
func decodeAVX2URI(dst []byte, src []byte, lut *int8) (int, int)
+143
View File
@@ -0,0 +1,143 @@
// Code generated by command: go run decode_asm.go -pkg base64 -out ../base64/decode_amd64.s -stubs ../base64/decode_amd64.go. DO NOT EDIT.
//go:build !purego
#include "textflag.h"
DATA b64_dec_lut_hi<>+0(SB)/8, $0x0804080402011010
DATA b64_dec_lut_hi<>+8(SB)/8, $0x1010101010101010
DATA b64_dec_lut_hi<>+16(SB)/8, $0x0804080402011010
DATA b64_dec_lut_hi<>+24(SB)/8, $0x1010101010101010
GLOBL b64_dec_lut_hi<>(SB), RODATA|NOPTR, $32
DATA b64_dec_madd1<>+0(SB)/8, $0x0140014001400140
DATA b64_dec_madd1<>+8(SB)/8, $0x0140014001400140
DATA b64_dec_madd1<>+16(SB)/8, $0x0140014001400140
DATA b64_dec_madd1<>+24(SB)/8, $0x0140014001400140
GLOBL b64_dec_madd1<>(SB), RODATA|NOPTR, $32
DATA b64_dec_madd2<>+0(SB)/8, $0x0001100000011000
DATA b64_dec_madd2<>+8(SB)/8, $0x0001100000011000
DATA b64_dec_madd2<>+16(SB)/8, $0x0001100000011000
DATA b64_dec_madd2<>+24(SB)/8, $0x0001100000011000
GLOBL b64_dec_madd2<>(SB), RODATA|NOPTR, $32
DATA b64_dec_shuf_lo<>+0(SB)/8, $0x0000000000000000
DATA b64_dec_shuf_lo<>+8(SB)/8, $0x0600010200000000
GLOBL b64_dec_shuf_lo<>(SB), RODATA|NOPTR, $16
DATA b64_dec_shuf<>+0(SB)/8, $0x090a040506000102
DATA b64_dec_shuf<>+8(SB)/8, $0x000000000c0d0e08
DATA b64_dec_shuf<>+16(SB)/8, $0x0c0d0e08090a0405
DATA b64_dec_shuf<>+24(SB)/8, $0x0000000000000000
GLOBL b64_dec_shuf<>(SB), RODATA|NOPTR, $32
// func decodeAVX2(dst []byte, src []byte, lut *int8) (int, int)
// Requires: AVX, AVX2, SSE4.1
TEXT ·decodeAVX2(SB), NOSPLIT, $0-72
MOVQ dst_base+0(FP), AX
MOVQ src_base+24(FP), DX
MOVQ lut+48(FP), SI
MOVQ src_len+32(FP), DI
MOVB $0x2f, CL
PINSRB $0x00, CX, X8
VPBROADCASTB X8, Y8
XORQ CX, CX
XORQ BX, BX
VPXOR Y7, Y7, Y7
VPERMQ $0x44, (SI), Y6
VPERMQ $0x44, 16(SI), Y4
VMOVDQA b64_dec_lut_hi<>+0(SB), Y5
loop:
VMOVDQU (DX)(BX*1), Y0
VPSRLD $0x04, Y0, Y2
VPAND Y8, Y0, Y3
VPSHUFB Y3, Y4, Y3
VPAND Y8, Y2, Y2
VPSHUFB Y2, Y5, Y9
VPTEST Y9, Y3
JNE done
VPCMPEQB Y8, Y0, Y3
VPADDB Y3, Y2, Y2
VPSHUFB Y2, Y6, Y2
VPADDB Y0, Y2, Y0
VPMADDUBSW b64_dec_madd1<>+0(SB), Y0, Y0
VPMADDWD b64_dec_madd2<>+0(SB), Y0, Y0
VEXTRACTI128 $0x01, Y0, X1
VPSHUFB b64_dec_shuf_lo<>+0(SB), X1, X1
VPSHUFB b64_dec_shuf<>+0(SB), Y0, Y0
VPBLENDD $0x08, Y1, Y0, Y1
VPBLENDD $0xc0, Y7, Y1, Y1
VMOVDQU Y1, (AX)(CX*1)
ADDQ $0x18, CX
ADDQ $0x20, BX
SUBQ $0x20, DI
CMPQ DI, $0x2d
JB done
JMP loop
done:
MOVQ CX, ret+56(FP)
MOVQ BX, ret1+64(FP)
VZEROUPPER
RET
// func decodeAVX2URI(dst []byte, src []byte, lut *int8) (int, int)
// Requires: AVX, AVX2, SSE4.1
TEXT ·decodeAVX2URI(SB), NOSPLIT, $0-72
MOVB $0x2f, AL
PINSRB $0x00, AX, X0
VPBROADCASTB X0, Y0
MOVB $0x5f, AL
PINSRB $0x00, AX, X1
VPBROADCASTB X1, Y1
MOVQ dst_base+0(FP), AX
MOVQ src_base+24(FP), DX
MOVQ lut+48(FP), SI
MOVQ src_len+32(FP), DI
MOVB $0x2f, CL
PINSRB $0x00, CX, X10
VPBROADCASTB X10, Y10
XORQ CX, CX
XORQ BX, BX
VPXOR Y9, Y9, Y9
VPERMQ $0x44, (SI), Y8
VPERMQ $0x44, 16(SI), Y6
VMOVDQA b64_dec_lut_hi<>+0(SB), Y7
loop:
VMOVDQU (DX)(BX*1), Y2
VPCMPEQB Y2, Y1, Y4
VPBLENDVB Y4, Y0, Y2, Y2
VPSRLD $0x04, Y2, Y4
VPAND Y10, Y2, Y5
VPSHUFB Y5, Y6, Y5
VPAND Y10, Y4, Y4
VPSHUFB Y4, Y7, Y11
VPTEST Y11, Y5
JNE done
VPCMPEQB Y10, Y2, Y5
VPADDB Y5, Y4, Y4
VPSHUFB Y4, Y8, Y4
VPADDB Y2, Y4, Y2
VPMADDUBSW b64_dec_madd1<>+0(SB), Y2, Y2
VPMADDWD b64_dec_madd2<>+0(SB), Y2, Y2
VEXTRACTI128 $0x01, Y2, X3
VPSHUFB b64_dec_shuf_lo<>+0(SB), X3, X3
VPSHUFB b64_dec_shuf<>+0(SB), Y2, Y2
VPBLENDD $0x08, Y3, Y2, Y3
VPBLENDD $0xc0, Y9, Y3, Y3
VMOVDQU Y3, (AX)(CX*1)
ADDQ $0x18, CX
ADDQ $0x20, BX
SUBQ $0x20, DI
CMPQ DI, $0x2d
JB done
JMP loop
done:
MOVQ CX, ret+56(FP)
MOVQ BX, ret1+64(FP)
VZEROUPPER
RET
+7
View File
@@ -0,0 +1,7 @@
//go:build !purego
// +build !purego
package base64
func decodeARM64(dst []byte, src []byte, lut *int8) (int, int)
func decodeStdARM64(dst []byte, src []byte, lut *int8) (int, int)
+213
View File
@@ -0,0 +1,213 @@
#include "textflag.h"
#define LOAD_ARGS() \
MOVD dst_base+0(FP), R0; \
MOVD R0, R3; \
MOVD src_base+24(FP), R1; \
MOVD R1, R4; \
MOVD src_len+32(FP), R2; \
BIC $31, R2, R2; \
ADD R1, R2, R2
#define LOAD_ARG_LUT() \
MOVD lut+48(FP), R5; \
VLD2R (R5), [V0.B16, V1.B16]
#define LOAD_CONST_LUT() \
MOVD $·mask_lut(SB), R6; \
MOVD $·bpos_lut(SB), R7; \
MOVD $·shft_lut(SB), R8; \
VLD1 (R6), [V2.B16]; \
VLD1 (R7), [V3.B16]; \
VLD1 (R8), [V4.B16]; \
VMOVI $43, V5.B8; \
VMOVI $47, V6.B8; \
VMOVI $15, V7.B8; \
VMOVI $16, V8.B8; \
#define LOAD_INPUT() \
VLD4 (R4), [V10.B8, V11.B8, V12.B8, V13.B8]
#define COMPARE_INPUT(v) \
VCMEQ V10.B8, v.B8, V14.B8; \
VCMEQ V11.B8, v.B8, V15.B8; \
VCMEQ V12.B8, v.B8, V16.B8; \
VCMEQ V13.B8, v.B8, V17.B8
#define UPDATE_INPUT(v) \
VBIT V14.B8, v.B8, V10.B8; \
VBIT V15.B8, v.B8, V11.B8; \
VBIT V16.B8, v.B8, V12.B8; \
VBIT V17.B8, v.B8, V13.B8
#define DECODE_INPUT(goto_err) \
/* Create hi/lo nibles */ \
VUSHR $4, V10.B8, V18.B8; \
VUSHR $4, V11.B8, V19.B8; \
VUSHR $4, V12.B8, V20.B8; \
VUSHR $4, V13.B8, V21.B8; \
VAND V7.B8, V10.B8, V22.B8; \
VAND V7.B8, V11.B8, V23.B8; \
VAND V7.B8, V12.B8, V24.B8; \
VAND V7.B8, V13.B8, V25.B8; \
/* Detect invalid input characters */ \
VTBL V22.B8, [V2.B8], V22.B8; \
VTBL V23.B8, [V2.B8], V23.B8; \
VTBL V24.B8, [V2.B8], V24.B8; \
VTBL V25.B8, [V2.B8], V25.B8; \
VTBL V18.B8, [V3.B8], V26.B8; \
VTBL V19.B8, [V3.B8], V27.B8; \
VTBL V20.B8, [V3.B8], V28.B8; \
VTBL V21.B8, [V3.B8], V29.B8; \
VAND V22.B8, V26.B8, V26.B8; \
VAND V23.B8, V27.B8, V27.B8; \
VAND V24.B8, V28.B8, V28.B8; \
VAND V25.B8, V29.B8, V29.B8; \
WORD $0x0e209b5a /* VCMEQ $0, V26.B8, V26.B8 */; \
WORD $0x0e209b7b /* VCMEQ $0, V27.B8, V27.B8 */; \
WORD $0x0e209b9c /* VCMEQ $0, V28.B8, V28.B8 */; \
WORD $0x0e209bbd /* VCMEQ $0, V29.B8, V29.B8 */; \
VORR V26.B8, V27.B8, V26.B8; \
VORR V28.B8, V29.B8, V28.B8; \
VORR V26.B8, V28.B8, V26.B8; \
VMOV V26.D[0], R5; \
VMOV V26.D[1], R6; \
ORR R6, R5; \
CBNZ R5, goto_err; \
/* Shift hi nibles */ \
VTBL V18.B8, [V4.B8], V18.B8; \
VTBL V19.B8, [V4.B8], V19.B8; \
VTBL V20.B8, [V4.B8], V20.B8; \
VTBL V21.B8, [V4.B8], V21.B8; \
VBIT V14.B8, V8.B8, V18.B8; \
VBIT V15.B8, V8.B8, V19.B8; \
VBIT V16.B8, V8.B8, V20.B8; \
VBIT V17.B8, V8.B8, V21.B8; \
/* Combine results */ \
VADD V18.B8, V10.B8, V10.B8; \
VADD V19.B8, V11.B8, V11.B8; \
VADD V20.B8, V12.B8, V12.B8; \
VADD V21.B8, V13.B8, V13.B8; \
VUSHR $4, V11.B8, V14.B8; \
VUSHR $2, V12.B8, V15.B8; \
VSHL $2, V10.B8, V10.B8; \
VSHL $4, V11.B8, V11.B8; \
VSHL $6, V12.B8, V12.B8; \
VORR V10.B8, V14.B8, V16.B8; \
VORR V11.B8, V15.B8, V17.B8; \
VORR V12.B8, V13.B8, V18.B8
#define ADVANCE_LOOP(goto_loop) \
VST3.P [V16.B8, V17.B8, V18.B8], 24(R3); \
ADD $32, R4; \
CMP R4, R2; \
BGT goto_loop
#define RETURN() \
SUB R0, R3; \
SUB R1, R4; \
MOVD R3, ret+56(FP); \
MOVD R4, ret1+64(FP); \
RET
// func decodeARM64(dst []byte, src []byte, lut *int8) (int, int)
TEXT ·decodeARM64(SB),NOSPLIT,$0-72
LOAD_ARGS()
LOAD_ARG_LUT()
LOAD_CONST_LUT()
loop:
LOAD_INPUT()
// Compare and normalize the 63rd and 64th characters
COMPARE_INPUT(V0)
UPDATE_INPUT(V5)
COMPARE_INPUT(V1)
UPDATE_INPUT(V6)
DECODE_INPUT(done) // Detect invalid input characters
ADVANCE_LOOP(loop) // Store results and continue
done:
// RETURN() replacing the macro to please go vet.
SUB R0, R3;
SUB R1, R4;
MOVD R3, ret+56(FP);
MOVD R4, ret1+64(FP);
RET
// func decodeStdARM64(dst []byte, src []byte, lut *int8) (int, int)
TEXT ·decodeStdARM64(SB),NOSPLIT,$0-72
LOAD_ARGS()
LOAD_CONST_LUT()
loop:
LOAD_INPUT()
COMPARE_INPUT(V6) // Compare to '+'
DECODE_INPUT(done) // Detect invalid input characters
ADVANCE_LOOP(loop) // Store results and continue
done:
// RETURN() replacing the macro to please go vet.
SUB R0, R3;
SUB R1, R4;
MOVD R3, ret+56(FP);
MOVD R4, ret1+64(FP);
RET
DATA ·mask_lut+0x00(SB)/1, $0xa8
DATA ·mask_lut+0x01(SB)/1, $0xf8
DATA ·mask_lut+0x02(SB)/1, $0xf8
DATA ·mask_lut+0x03(SB)/1, $0xf8
DATA ·mask_lut+0x04(SB)/1, $0xf8
DATA ·mask_lut+0x05(SB)/1, $0xf8
DATA ·mask_lut+0x06(SB)/1, $0xf8
DATA ·mask_lut+0x07(SB)/1, $0xf8
DATA ·mask_lut+0x08(SB)/1, $0xf8
DATA ·mask_lut+0x09(SB)/1, $0xf8
DATA ·mask_lut+0x0a(SB)/1, $0xf0
DATA ·mask_lut+0x0b(SB)/1, $0x54
DATA ·mask_lut+0x0c(SB)/1, $0x50
DATA ·mask_lut+0x0d(SB)/1, $0x50
DATA ·mask_lut+0x0e(SB)/1, $0x50
DATA ·mask_lut+0x0f(SB)/1, $0x54
GLOBL ·mask_lut(SB), NOPTR|RODATA, $16
DATA ·bpos_lut+0x00(SB)/1, $0x01
DATA ·bpos_lut+0x01(SB)/1, $0x02
DATA ·bpos_lut+0x02(SB)/1, $0x04
DATA ·bpos_lut+0x03(SB)/1, $0x08
DATA ·bpos_lut+0x04(SB)/1, $0x10
DATA ·bpos_lut+0x05(SB)/1, $0x20
DATA ·bpos_lut+0x06(SB)/1, $0x40
DATA ·bpos_lut+0x07(SB)/1, $0x80
DATA ·bpos_lut+0x08(SB)/1, $0x00
DATA ·bpos_lut+0x09(SB)/1, $0x00
DATA ·bpos_lut+0x0a(SB)/1, $0x00
DATA ·bpos_lut+0x0b(SB)/1, $0x00
DATA ·bpos_lut+0x0c(SB)/1, $0x00
DATA ·bpos_lut+0x0d(SB)/1, $0x00
DATA ·bpos_lut+0x0e(SB)/1, $0x00
DATA ·bpos_lut+0x0f(SB)/1, $0x00
GLOBL ·bpos_lut(SB), NOPTR|RODATA, $16
DATA ·shft_lut+0x00(SB)/1, $0x00
DATA ·shft_lut+0x01(SB)/1, $0x00
DATA ·shft_lut+0x02(SB)/1, $0x13
DATA ·shft_lut+0x03(SB)/1, $0x04
DATA ·shft_lut+0x04(SB)/1, $0xbf
DATA ·shft_lut+0x05(SB)/1, $0xbf
DATA ·shft_lut+0x06(SB)/1, $0xb9
DATA ·shft_lut+0x07(SB)/1, $0xb9
DATA ·shft_lut+0x08(SB)/1, $0x00
DATA ·shft_lut+0x09(SB)/1, $0x00
DATA ·shft_lut+0x0a(SB)/1, $0x00
DATA ·shft_lut+0x0b(SB)/1, $0x00
DATA ·shft_lut+0x0c(SB)/1, $0x00
DATA ·shft_lut+0x0d(SB)/1, $0x00
DATA ·shft_lut+0x0e(SB)/1, $0x00
DATA ·shft_lut+0x0f(SB)/1, $0x00
GLOBL ·shft_lut(SB), NOPTR|RODATA, $16
+7
View File
@@ -0,0 +1,7 @@
// Code generated by command: go run encode_asm.go -pkg base64 -out ../base64/encode_amd64.s -stubs ../base64/encode_amd64.go. DO NOT EDIT.
//go:build !purego
package base64
func encodeAVX2(dst []byte, src []byte, lut *int8) (int, int)
+87
View File
@@ -0,0 +1,87 @@
// Code generated by command: go run encode_asm.go -pkg base64 -out ../base64/encode_amd64.s -stubs ../base64/encode_amd64.go. DO NOT EDIT.
//go:build !purego
#include "textflag.h"
// func encodeAVX2(dst []byte, src []byte, lut *int8) (int, int)
// Requires: AVX, AVX2, SSE4.1
TEXT ·encodeAVX2(SB), NOSPLIT, $0-72
MOVQ dst_base+0(FP), AX
MOVQ src_base+24(FP), DX
MOVQ lut+48(FP), SI
MOVQ src_len+32(FP), DI
MOVB $0x33, CL
PINSRB $0x00, CX, X4
VPBROADCASTB X4, Y4
MOVB $0x19, CL
PINSRB $0x00, CX, X5
VPBROADCASTB X5, Y5
XORQ CX, CX
XORQ BX, BX
// Load the 16-byte LUT into both lanes of the register
VPERMQ $0x44, (SI), Y3
// Load the first block using a mask to avoid potential fault
VMOVDQU b64_enc_load<>+0(SB), Y0
VPMASKMOVD -4(DX)(BX*1), Y0, Y0
loop:
VPSHUFB b64_enc_shuf<>+0(SB), Y0, Y0
VPAND b64_enc_mask1<>+0(SB), Y0, Y1
VPSLLW $0x08, Y1, Y2
VPSLLW $0x04, Y1, Y1
VPBLENDW $0xaa, Y2, Y1, Y2
VPAND b64_enc_mask2<>+0(SB), Y0, Y1
VPMULHUW b64_enc_mult<>+0(SB), Y1, Y0
VPOR Y0, Y2, Y0
VPSUBUSB Y4, Y0, Y1
VPCMPGTB Y5, Y0, Y2
VPSUBB Y2, Y1, Y1
VPSHUFB Y1, Y3, Y1
VPADDB Y0, Y1, Y0
VMOVDQU Y0, (AX)(CX*1)
ADDQ $0x20, CX
ADDQ $0x18, BX
SUBQ $0x18, DI
CMPQ DI, $0x20
JB done
VMOVDQU -4(DX)(BX*1), Y0
JMP loop
done:
MOVQ CX, ret+56(FP)
MOVQ BX, ret1+64(FP)
VZEROUPPER
RET
DATA b64_enc_load<>+0(SB)/8, $0x8000000000000000
DATA b64_enc_load<>+8(SB)/8, $0x8000000080000000
DATA b64_enc_load<>+16(SB)/8, $0x8000000080000000
DATA b64_enc_load<>+24(SB)/8, $0x8000000080000000
GLOBL b64_enc_load<>(SB), RODATA|NOPTR, $32
DATA b64_enc_shuf<>+0(SB)/8, $0x0809070805060405
DATA b64_enc_shuf<>+8(SB)/8, $0x0e0f0d0e0b0c0a0b
DATA b64_enc_shuf<>+16(SB)/8, $0x0405030401020001
DATA b64_enc_shuf<>+24(SB)/8, $0x0a0b090a07080607
GLOBL b64_enc_shuf<>(SB), RODATA|NOPTR, $32
DATA b64_enc_mask1<>+0(SB)/8, $0x003f03f0003f03f0
DATA b64_enc_mask1<>+8(SB)/8, $0x003f03f0003f03f0
DATA b64_enc_mask1<>+16(SB)/8, $0x003f03f0003f03f0
DATA b64_enc_mask1<>+24(SB)/8, $0x003f03f0003f03f0
GLOBL b64_enc_mask1<>(SB), RODATA|NOPTR, $32
DATA b64_enc_mask2<>+0(SB)/8, $0x0fc0fc000fc0fc00
DATA b64_enc_mask2<>+8(SB)/8, $0x0fc0fc000fc0fc00
DATA b64_enc_mask2<>+16(SB)/8, $0x0fc0fc000fc0fc00
DATA b64_enc_mask2<>+24(SB)/8, $0x0fc0fc000fc0fc00
GLOBL b64_enc_mask2<>(SB), RODATA|NOPTR, $32
DATA b64_enc_mult<>+0(SB)/8, $0x0400004004000040
DATA b64_enc_mult<>+8(SB)/8, $0x0400004004000040
DATA b64_enc_mult<>+16(SB)/8, $0x0400004004000040
DATA b64_enc_mult<>+24(SB)/8, $0x0400004004000040
GLOBL b64_enc_mult<>(SB), RODATA|NOPTR, $32
+6
View File
@@ -0,0 +1,6 @@
//go:build !purego
// +build !purego
package base64
func encodeARM64(dst []byte, src []byte, lut *int8) (int, int)
+97
View File
@@ -0,0 +1,97 @@
#include "textflag.h"
#define Rdst R0
#define Rsrc R1
#define Rlen R2
#define Rwr R3
#define Rrem R4
#define Rtmp R5
#define Vlut V0
#define Vfld0 V6
#define Vfld1 V7
#define Vfld2 V8
#define Vfld3 V9
#define Vsrc0 V10
#define Vsrc1 V11
#define Vsrc2 V12
#define Vr0a V13
#define Vr1a V14
#define Vr2a V15
#define Vr3a V16
#define Vr0b V17
#define Vr1b V18
#define Vr2b V19
#define Vr3b V20
// func encodeARM64(dst []byte, src []byte, lut *int8) (int, int)
TEXT ·encodeARM64(SB),NOSPLIT,$0-72
// Load dst/src info
MOVD dst_base+0(FP), Rdst
MOVD src_base+24(FP), Rsrc
MOVD src_len+32(FP), Rlen
MOVD lut+48(FP), Rtmp
VLD1 (Rtmp), [Vlut.B16]
MOVD Rlen, Rrem
MOVD Rdst, Rwr
VMOVI $51, V1.B16
VMOVI $26, V2.B16
VMOVI $63, V3.B16
VMOVI $13, V4.B16
loop:
VLD3.P 48(Rsrc), [Vsrc0.B16, Vsrc1.B16, Vsrc2.B16]
// Split 3 source blocks into 4 lookup inputs
VUSHR $2, Vsrc0.B16, Vfld0.B16
VUSHR $4, Vsrc1.B16, Vfld1.B16
VUSHR $6, Vsrc2.B16, Vfld2.B16
VSHL $4, Vsrc0.B16, Vsrc0.B16
VSHL $2, Vsrc1.B16, Vsrc1.B16
VORR Vsrc0.B16, Vfld1.B16, Vfld1.B16
VORR Vsrc1.B16, Vfld2.B16, Vfld2.B16
VAND V3.B16, Vfld1.B16, Vfld1.B16
VAND V3.B16, Vfld2.B16, Vfld2.B16
VAND V3.B16, Vsrc2.B16, Vfld3.B16
WORD $0x6e212ccd // VUQSUB V1.B16, Vfld0.B16, Vr0a.B16
WORD $0x4e263451 // VCMGT V2.B16, Vfld0.B16, Vr0b.B16
VAND V4.B16, Vr0b.B16, Vr0b.B16
VORR Vr0b.B16, Vr0a.B16, Vr0a.B16
WORD $0x6e212cee // VUQSUB V1.B16, Vfld1.B16, Vr1a.B16
WORD $0x4e273452 // VCMGT V2.B16, Vfld1.B16, Vr1b.B16
VAND V4.B16, Vr1b.B16, Vr1b.B16
VORR Vr1b.B16, Vr1a.B16, Vr1a.B16
WORD $0x6e212d0f // VUQSUB V1.B16, Vfld2.B16, Vr2a.B16
WORD $0x4e283453 // VCMGT V2.B16, Vfld2.B16, Vr2b.B16
VAND V4.B16, Vr2b.B16, Vr2b.B16
VORR Vr2b.B16, Vr2a.B16, Vr2a.B16
WORD $0x6e212d30 // VUQSUB V1.B16, Vfld3.B16, Vr3a.B16
WORD $0x4e293454 // VCMGT V2.B16, Vfld3.B16, Vr3b.B16
VAND V4.B16, Vr3b.B16, Vr3b.B16
VORR Vr3b.B16, Vr3a.B16, Vr3a.B16
// Add result of lookup table to each field
VTBL Vr0a.B16, [Vlut.B16], Vr0a.B16
VADD Vr0a.B16, Vfld0.B16, Vfld0.B16
VTBL Vr1a.B16, [Vlut.B16], Vr1a.B16
VADD Vr1a.B16, Vfld1.B16, Vfld1.B16
VTBL Vr2a.B16, [Vlut.B16], Vr2a.B16
VADD Vr2a.B16, Vfld2.B16, Vfld2.B16
VTBL Vr3a.B16, [Vlut.B16], Vr3a.B16
VADD Vr3a.B16, Vfld3.B16, Vfld3.B16
VST4.P [Vfld0.B16, Vfld1.B16, Vfld2.B16, Vfld3.B16], 64(Rwr)
SUB $48, Rrem
CMP $48, Rrem
BGE loop
done:
SUB Rdst, Rwr
SUB Rrem, Rlen
MOVD Rwr, ret+56(FP)
MOVD Rlen, ret1+64(FP)
RET
+80
View File
@@ -0,0 +1,80 @@
package arm
import (
"github.com/segmentio/asm/cpu/cpuid"
. "golang.org/x/sys/cpu"
)
type CPU cpuid.CPU
func (cpu CPU) Has(feature Feature) bool {
return cpuid.CPU(cpu).Has(cpuid.Feature(feature))
}
func (cpu *CPU) set(feature Feature, enable bool) {
(*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable)
}
type Feature cpuid.Feature
const (
SWP Feature = 1 << iota // SWP instruction support
HALF // Half-word load and store support
THUMB // ARM Thumb instruction set
BIT26 // Address space limited to 26-bits
FASTMUL // 32-bit operand, 64-bit result multiplication support
FPA // Floating point arithmetic support
VFP // Vector floating point support
EDSP // DSP Extensions support
JAVA // Java instruction set
IWMMXT // Intel Wireless MMX technology support
CRUNCH // MaverickCrunch context switching and handling
THUMBEE // Thumb EE instruction set
NEON // NEON instruction set
VFPv3 // Vector floating point version 3 support
VFPv3D16 // Vector floating point version 3 D8-D15
TLS // Thread local storage support
VFPv4 // Vector floating point version 4 support
IDIVA // Integer divide instruction support in ARM mode
IDIVT // Integer divide instruction support in Thumb mode
VFPD32 // Vector floating point version 3 D15-D31
LPAE // Large Physical Address Extensions
EVTSTRM // Event stream support
AES // AES hardware implementation
PMULL // Polynomial multiplication instruction set
SHA1 // SHA1 hardware implementation
SHA2 // SHA2 hardware implementation
CRC32 // CRC32 hardware implementation
)
func ABI() CPU {
cpu := CPU(0)
cpu.set(SWP, ARM.HasSWP)
cpu.set(HALF, ARM.HasHALF)
cpu.set(THUMB, ARM.HasTHUMB)
cpu.set(BIT26, ARM.Has26BIT)
cpu.set(FASTMUL, ARM.HasFASTMUL)
cpu.set(FPA, ARM.HasFPA)
cpu.set(VFP, ARM.HasVFP)
cpu.set(EDSP, ARM.HasEDSP)
cpu.set(JAVA, ARM.HasJAVA)
cpu.set(IWMMXT, ARM.HasIWMMXT)
cpu.set(CRUNCH, ARM.HasCRUNCH)
cpu.set(THUMBEE, ARM.HasTHUMBEE)
cpu.set(NEON, ARM.HasNEON)
cpu.set(VFPv3, ARM.HasVFPv3)
cpu.set(VFPv3D16, ARM.HasVFPv3D16)
cpu.set(TLS, ARM.HasTLS)
cpu.set(VFPv4, ARM.HasVFPv4)
cpu.set(IDIVA, ARM.HasIDIVA)
cpu.set(IDIVT, ARM.HasIDIVT)
cpu.set(VFPD32, ARM.HasVFPD32)
cpu.set(LPAE, ARM.HasLPAE)
cpu.set(EVTSTRM, ARM.HasEVTSTRM)
cpu.set(AES, ARM.HasAES)
cpu.set(PMULL, ARM.HasPMULL)
cpu.set(SHA1, ARM.HasSHA1)
cpu.set(SHA2, ARM.HasSHA2)
cpu.set(CRC32, ARM.HasCRC32)
return cpu
}
+74
View File
@@ -0,0 +1,74 @@
package arm64
import (
"github.com/segmentio/asm/cpu/cpuid"
. "golang.org/x/sys/cpu"
)
type CPU cpuid.CPU
func (cpu CPU) Has(feature Feature) bool {
return cpuid.CPU(cpu).Has(cpuid.Feature(feature))
}
func (cpu *CPU) set(feature Feature, enable bool) {
(*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable)
}
type Feature cpuid.Feature
const (
FP Feature = 1 << iota // Floating-point instruction set (always available)
ASIMD // Advanced SIMD (always available)
EVTSTRM // Event stream support
AES // AES hardware implementation
PMULL // Polynomial multiplication instruction set
SHA1 // SHA1 hardware implementation
SHA2 // SHA2 hardware implementation
CRC32 // CRC32 hardware implementation
ATOMICS // Atomic memory operation instruction set
FPHP // Half precision floating-point instruction set
ASIMDHP // Advanced SIMD half precision instruction set
CPUID // CPUID identification scheme registers
ASIMDRDM // Rounding double multiply add/subtract instruction set
JSCVT // Javascript conversion from floating-point to integer
FCMA // Floating-point multiplication and addition of complex numbers
LRCPC // Release Consistent processor consistent support
DCPOP // Persistent memory support
SHA3 // SHA3 hardware implementation
SM3 // SM3 hardware implementation
SM4 // SM4 hardware implementation
ASIMDDP // Advanced SIMD double precision instruction set
SHA512 // SHA512 hardware implementation
SVE // Scalable Vector Extensions
ASIMDFHM // Advanced SIMD multiplication FP16 to FP32
)
func ABI() CPU {
cpu := CPU(0)
cpu.set(FP, ARM64.HasFP)
cpu.set(ASIMD, ARM64.HasASIMD)
cpu.set(EVTSTRM, ARM64.HasEVTSTRM)
cpu.set(AES, ARM64.HasAES)
cpu.set(PMULL, ARM64.HasPMULL)
cpu.set(SHA1, ARM64.HasSHA1)
cpu.set(SHA2, ARM64.HasSHA2)
cpu.set(CRC32, ARM64.HasCRC32)
cpu.set(ATOMICS, ARM64.HasATOMICS)
cpu.set(FPHP, ARM64.HasFPHP)
cpu.set(ASIMDHP, ARM64.HasASIMDHP)
cpu.set(CPUID, ARM64.HasCPUID)
cpu.set(ASIMDRDM, ARM64.HasASIMDRDM)
cpu.set(JSCVT, ARM64.HasJSCVT)
cpu.set(FCMA, ARM64.HasFCMA)
cpu.set(LRCPC, ARM64.HasLRCPC)
cpu.set(DCPOP, ARM64.HasDCPOP)
cpu.set(SHA3, ARM64.HasSHA3)
cpu.set(SM3, ARM64.HasSM3)
cpu.set(SM4, ARM64.HasSM4)
cpu.set(ASIMDDP, ARM64.HasASIMDDP)
cpu.set(SHA512, ARM64.HasSHA512)
cpu.set(SVE, ARM64.HasSVE)
cpu.set(ASIMDFHM, ARM64.HasASIMDFHM)
return cpu
}
+22
View File
@@ -0,0 +1,22 @@
// Pakage cpu provides APIs to detect CPU features available at runtime.
package cpu
import (
"github.com/segmentio/asm/cpu/arm"
"github.com/segmentio/asm/cpu/arm64"
"github.com/segmentio/asm/cpu/x86"
)
var (
// X86 is the bitset representing the set of the x86 instruction sets are
// supported by the CPU.
X86 = x86.ABI()
// ARM is the bitset representing which parts of the arm instruction sets
// are supported by the CPU.
ARM = arm.ABI()
// ARM64 is the bitset representing which parts of the arm64 instruction
// sets are supported by the CPU.
ARM64 = arm64.ABI()
)
+32
View File
@@ -0,0 +1,32 @@
// Package cpuid provides generic types used to represent CPU features supported
// by the architecture.
package cpuid
// CPU is a bitset of feature flags representing the capabilities of various CPU
// architeectures that this package provides optimized assembly routines for.
//
// The intent is to provide a stable ABI between the Go code that generate the
// assembly, and the program that uses the library functions.
type CPU uint64
// Feature represents a single CPU feature.
type Feature uint64
const (
// None is a Feature value that has no CPU features enabled.
None Feature = 0
// All is a Feature value that has all CPU features enabled.
All Feature = 0xFFFFFFFFFFFFFFFF
)
func (cpu CPU) Has(feature Feature) bool {
return (Feature(cpu) & feature) == feature
}
func (cpu *CPU) Set(feature Feature, enabled bool) {
if enabled {
*cpu |= CPU(feature)
} else {
*cpu &= ^CPU(feature)
}
}
+76
View File
@@ -0,0 +1,76 @@
package x86
import (
"github.com/segmentio/asm/cpu/cpuid"
. "golang.org/x/sys/cpu"
)
type CPU cpuid.CPU
func (cpu CPU) Has(feature Feature) bool {
return cpuid.CPU(cpu).Has(cpuid.Feature(feature))
}
func (cpu *CPU) set(feature Feature, enable bool) {
(*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable)
}
type Feature cpuid.Feature
const (
SSE Feature = 1 << iota // SSE functions
SSE2 // P4 SSE functions
SSE3 // Prescott SSE3 functions
SSE41 // Penryn SSE4.1 functions
SSE42 // Nehalem SSE4.2 functions
SSE4A // AMD Barcelona microarchitecture SSE4a instructions
SSSE3 // Conroe SSSE3 functions
AVX // AVX functions
AVX2 // AVX2 functions
AVX512BF16 // AVX-512 BFLOAT16 Instructions
AVX512BITALG // AVX-512 Bit Algorithms
AVX512BW // AVX-512 Byte and Word Instructions
AVX512CD // AVX-512 Conflict Detection Instructions
AVX512DQ // AVX-512 Doubleword and Quadword Instructions
AVX512ER // AVX-512 Exponential and Reciprocal Instructions
AVX512F // AVX-512 Foundation
AVX512IFMA // AVX-512 Integer Fused Multiply-Add Instructions
AVX512PF // AVX-512 Prefetch Instructions
AVX512VBMI // AVX-512 Vector Bit Manipulation Instructions
AVX512VBMI2 // AVX-512 Vector Bit Manipulation Instructions, Version 2
AVX512VL // AVX-512 Vector Length Extensions
AVX512VNNI // AVX-512 Vector Neural Network Instructions
AVX512VP2INTERSECT // AVX-512 Intersect for D/Q
AVX512VPOPCNTDQ // AVX-512 Vector Population Count Doubleword and Quadword
CMOV // Conditional move
)
func ABI() CPU {
cpu := CPU(0)
cpu.set(SSE, true) // TODO: golang.org/x/sys/cpu assumes all CPUs have SEE?
cpu.set(SSE2, X86.HasSSE2)
cpu.set(SSE3, X86.HasSSE3)
cpu.set(SSE41, X86.HasSSE41)
cpu.set(SSE42, X86.HasSSE42)
cpu.set(SSE4A, false) // TODO: add upstream support in golang.org/x/sys/cpu?
cpu.set(SSSE3, X86.HasSSSE3)
cpu.set(AVX, X86.HasAVX)
cpu.set(AVX2, X86.HasAVX2)
cpu.set(AVX512BF16, X86.HasAVX512BF16)
cpu.set(AVX512BITALG, X86.HasAVX512BITALG)
cpu.set(AVX512BW, X86.HasAVX512BW)
cpu.set(AVX512CD, X86.HasAVX512CD)
cpu.set(AVX512DQ, X86.HasAVX512DQ)
cpu.set(AVX512ER, X86.HasAVX512ER)
cpu.set(AVX512F, X86.HasAVX512F)
cpu.set(AVX512IFMA, X86.HasAVX512IFMA)
cpu.set(AVX512PF, X86.HasAVX512PF)
cpu.set(AVX512VBMI, X86.HasAVX512VBMI)
cpu.set(AVX512VBMI2, X86.HasAVX512VBMI2)
cpu.set(AVX512VL, X86.HasAVX512VL)
cpu.set(AVX512VNNI, X86.HasAVX512VNNI)
cpu.set(AVX512VP2INTERSECT, false) // TODO: add upstream support in golang.org/x/sys/cpu?
cpu.set(AVX512VPOPCNTDQ, X86.HasAVX512VPOPCNTDQ)
cpu.set(CMOV, true) // TODO: golang.org/x/sys/cpu assumes all CPUs have CMOV?
return cpu
}
@@ -0,0 +1,20 @@
package unsafebytes
import "unsafe"
func Pointer(b []byte) *byte {
return *(**byte)(unsafe.Pointer(&b))
}
func String(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func BytesOf(s string) []byte {
return *(*[]byte)(unsafe.Pointer(&sliceHeader{str: s, cap: len(s)}))
}
type sliceHeader struct {
str string
cap int
}