github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/inverted/serialization.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package inverted 13 14 import ( 15 "bytes" 16 "encoding/binary" 17 "fmt" 18 "math" 19 20 "github.com/pkg/errors" 21 ) 22 23 // LexicographicallySortableFloat64 transforms a conversion to a 24 // lexicographically sortable byte slice. In general, for lexicographical 25 // sorting big endian notatino is required. Additionally the sign needs to be 26 // flipped in any case, but additionally each remaining byte also needs to be 27 // flipped if the number is negative 28 func LexicographicallySortableFloat64(in float64) ([]byte, error) { 29 buf := bytes.NewBuffer(nil) 30 31 err := binary.Write(buf, binary.BigEndian, in) 32 if err != nil { 33 return nil, errors.Wrap(err, "serialize float64 value as big endian") 34 } 35 36 var out []byte 37 if in >= 0 { 38 // on positive numbers only flip the sign 39 out = buf.Bytes() 40 firstByte := out[0] ^ 0x80 41 out = append([]byte{firstByte}, out[1:]...) 42 } else { 43 // on negative numbers flip every bit 44 out = make([]byte, 8) 45 for i, b := range buf.Bytes() { 46 out[i] = b ^ 0xFF 47 } 48 } 49 50 return out, nil 51 } 52 53 // ParseLexicographicallySortableFloat64 reverses the changes in 54 // LexicographicallySortableFloat64 55 func ParseLexicographicallySortableFloat64(in []byte) (float64, error) { 56 if len(in) != 8 { 57 return 0, fmt.Errorf("float64 must be 8 bytes long, got: %d", len(in)) 58 } 59 60 flipped := make([]byte, 8) 61 if in[0]&0x80 == 0x80 { 62 // encoded as negative means it was originally positive, so we only need to 63 // flip the sign 64 flipped[0] = in[0] ^ 0x80 65 66 // the remainder can be copied 67 for i := 1; i < 8; i++ { 68 flipped[i] = in[i] 69 } 70 } else { 71 // encoded as positive means it was originally negative, so we need to flip 72 // everything 73 for i := 0; i < 8; i++ { 74 flipped[i] = in[i] ^ 0xFF 75 } 76 } 77 78 r := bytes.NewReader(flipped) 79 var value float64 80 81 err := binary.Read(r, binary.BigEndian, &value) 82 if err != nil { 83 return 0, errors.Wrap(err, "deserialize float64 value as big endian") 84 } 85 86 return value, nil 87 } 88 89 // LexicographicallySortableInt64 performs a conversion to a lexicographically 90 // sortable byte slice. For this, big endian notation is required and the sign 91 // must be flipped 92 func LexicographicallySortableInt64(in int64) ([]byte, error) { 93 buf := bytes.NewBuffer(nil) 94 asInt64 := int64(in) 95 96 // flip the sign 97 asInt64 = asInt64 ^ math.MinInt64 98 99 err := binary.Write(buf, binary.BigEndian, asInt64) 100 if err != nil { 101 return nil, errors.Wrap(err, "serialize int value as big endian") 102 } 103 104 return buf.Bytes(), nil 105 } 106 107 // ParseLexicographicallySortableInt64 reverses the changes in 108 // LexicographicallySortableInt64 109 func ParseLexicographicallySortableInt64(in []byte) (int64, error) { 110 if len(in) != 8 { 111 return 0, fmt.Errorf("int64 must be 8 bytes long, got: %d", len(in)) 112 } 113 114 r := bytes.NewReader(in) 115 var value int64 116 117 err := binary.Read(r, binary.BigEndian, &value) 118 if err != nil { 119 return 0, errors.Wrap(err, "deserialize int64 value as big endian") 120 } 121 122 return value ^ math.MinInt64, nil 123 } 124 125 // LexicographicallySortableUint64 performs a conversion to a lexicographically 126 // sortable byte slice. For this, big endian notation is required. 127 func LexicographicallySortableUint64(in uint64) ([]byte, error) { 128 buf := bytes.NewBuffer(nil) 129 130 // no signs to flip as this is a uint 131 err := binary.Write(buf, binary.BigEndian, in) 132 if err != nil { 133 return nil, errors.Wrap(err, "serialize int value as big endian") 134 } 135 136 return buf.Bytes(), nil 137 } 138 139 // ParseLexicographicallySortableUint64 reverses the changes in 140 // LexicographicallySortableUint64 141 func ParseLexicographicallySortableUint64(in []byte) (uint64, error) { 142 if len(in) != 8 { 143 return 0, fmt.Errorf("uint64 must be 8 bytes long, got: %d", len(in)) 144 } 145 146 r := bytes.NewReader(in) 147 var value uint64 148 149 err := binary.Read(r, binary.BigEndian, &value) 150 if err != nil { 151 return 0, errors.Wrap(err, "deserialize uint64 value as big endian") 152 } 153 154 return value, nil 155 }