github.com/KinWaiYuen/client-go/v2@v2.5.4/util/codec/number.go (about)

     1  // Copyright 2021 TiKV Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // NOTE: The code in this file is based on code from the
    16  // TiDB project, licensed under the Apache License v 2.0
    17  //
    18  // https://github.com/pingcap/tidb/tree/cc5e161ac06827589c4966674597c137cc9e809c/store/tikv/util/codec/number.go
    19  //
    20  
    21  // Copyright 2015 PingCAP, Inc.
    22  //
    23  // Licensed under the Apache License, Version 2.0 (the "License");
    24  // you may not use this file except in compliance with the License.
    25  // You may obtain a copy of the License at
    26  //
    27  //     http://www.apache.org/licenses/LICENSE-2.0
    28  //
    29  // Unless required by applicable law or agreed to in writing, software
    30  // distributed under the License is distributed on an "AS IS" BASIS,
    31  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    32  // See the License for the specific language governing permissions and
    33  // limitations under the License.
    34  
    35  package codec
    36  
    37  import (
    38  	"encoding/binary"
    39  	"math"
    40  
    41  	"github.com/pingcap/errors"
    42  )
    43  
    44  const signMask uint64 = 0x8000000000000000
    45  
    46  // EncodeIntToCmpUint make int v to comparable uint type
    47  func EncodeIntToCmpUint(v int64) uint64 {
    48  	return uint64(v) ^ signMask
    49  }
    50  
    51  // DecodeCmpUintToInt decodes the u that encoded by EncodeIntToCmpUint
    52  func DecodeCmpUintToInt(u uint64) int64 {
    53  	return int64(u ^ signMask)
    54  }
    55  
    56  // EncodeInt appends the encoded value to slice b and returns the appended slice.
    57  // EncodeInt guarantees that the encoded value is in ascending order for comparison.
    58  func EncodeInt(b []byte, v int64) []byte {
    59  	var data [8]byte
    60  	u := EncodeIntToCmpUint(v)
    61  	binary.BigEndian.PutUint64(data[:], u)
    62  	return append(b, data[:]...)
    63  }
    64  
    65  // EncodeIntDesc appends the encoded value to slice b and returns the appended slice.
    66  // EncodeIntDesc guarantees that the encoded value is in descending order for comparison.
    67  func EncodeIntDesc(b []byte, v int64) []byte {
    68  	var data [8]byte
    69  	u := EncodeIntToCmpUint(v)
    70  	binary.BigEndian.PutUint64(data[:], ^u)
    71  	return append(b, data[:]...)
    72  }
    73  
    74  // DecodeInt decodes value encoded by EncodeInt before.
    75  // It returns the leftover un-decoded slice, decoded value if no error.
    76  func DecodeInt(b []byte) ([]byte, int64, error) {
    77  	if len(b) < 8 {
    78  		return nil, 0, errors.New("insufficient bytes to decode value")
    79  	}
    80  
    81  	u := binary.BigEndian.Uint64(b[:8])
    82  	v := DecodeCmpUintToInt(u)
    83  	b = b[8:]
    84  	return b, v, nil
    85  }
    86  
    87  // DecodeIntDesc decodes value encoded by EncodeInt before.
    88  // It returns the leftover un-decoded slice, decoded value if no error.
    89  func DecodeIntDesc(b []byte) ([]byte, int64, error) {
    90  	if len(b) < 8 {
    91  		return nil, 0, errors.New("insufficient bytes to decode value")
    92  	}
    93  
    94  	u := binary.BigEndian.Uint64(b[:8])
    95  	v := DecodeCmpUintToInt(^u)
    96  	b = b[8:]
    97  	return b, v, nil
    98  }
    99  
   100  // EncodeUint appends the encoded value to slice b and returns the appended slice.
   101  // EncodeUint guarantees that the encoded value is in ascending order for comparison.
   102  func EncodeUint(b []byte, v uint64) []byte {
   103  	var data [8]byte
   104  	binary.BigEndian.PutUint64(data[:], v)
   105  	return append(b, data[:]...)
   106  }
   107  
   108  // EncodeUintDesc appends the encoded value to slice b and returns the appended slice.
   109  // EncodeUintDesc guarantees that the encoded value is in descending order for comparison.
   110  func EncodeUintDesc(b []byte, v uint64) []byte {
   111  	var data [8]byte
   112  	binary.BigEndian.PutUint64(data[:], ^v)
   113  	return append(b, data[:]...)
   114  }
   115  
   116  // DecodeUint decodes value encoded by EncodeUint before.
   117  // It returns the leftover un-decoded slice, decoded value if no error.
   118  func DecodeUint(b []byte) ([]byte, uint64, error) {
   119  	if len(b) < 8 {
   120  		return nil, 0, errors.New("insufficient bytes to decode value")
   121  	}
   122  
   123  	v := binary.BigEndian.Uint64(b[:8])
   124  	b = b[8:]
   125  	return b, v, nil
   126  }
   127  
   128  // DecodeUintDesc decodes value encoded by EncodeInt before.
   129  // It returns the leftover un-decoded slice, decoded value if no error.
   130  func DecodeUintDesc(b []byte) ([]byte, uint64, error) {
   131  	if len(b) < 8 {
   132  		return nil, 0, errors.New("insufficient bytes to decode value")
   133  	}
   134  
   135  	data := b[:8]
   136  	v := binary.BigEndian.Uint64(data)
   137  	b = b[8:]
   138  	return b, ^v, nil
   139  }
   140  
   141  // EncodeVarint appends the encoded value to slice b and returns the appended slice.
   142  // Note that the encoded result is not memcomparable.
   143  func EncodeVarint(b []byte, v int64) []byte {
   144  	var data [binary.MaxVarintLen64]byte
   145  	n := binary.PutVarint(data[:], v)
   146  	return append(b, data[:n]...)
   147  }
   148  
   149  // DecodeVarint decodes value encoded by EncodeVarint before.
   150  // It returns the leftover un-decoded slice, decoded value if no error.
   151  func DecodeVarint(b []byte) ([]byte, int64, error) {
   152  	v, n := binary.Varint(b)
   153  	if n > 0 {
   154  		return b[n:], v, nil
   155  	}
   156  	if n < 0 {
   157  		return nil, 0, errors.New("value larger than 64 bits")
   158  	}
   159  	return nil, 0, errors.New("insufficient bytes to decode value")
   160  }
   161  
   162  // EncodeUvarint appends the encoded value to slice b and returns the appended slice.
   163  // Note that the encoded result is not memcomparable.
   164  func EncodeUvarint(b []byte, v uint64) []byte {
   165  	var data [binary.MaxVarintLen64]byte
   166  	n := binary.PutUvarint(data[:], v)
   167  	return append(b, data[:n]...)
   168  }
   169  
   170  // DecodeUvarint decodes value encoded by EncodeUvarint before.
   171  // It returns the leftover un-decoded slice, decoded value if no error.
   172  func DecodeUvarint(b []byte) ([]byte, uint64, error) {
   173  	v, n := binary.Uvarint(b)
   174  	if n > 0 {
   175  		return b[n:], v, nil
   176  	}
   177  	if n < 0 {
   178  		return nil, 0, errors.New("value larger than 64 bits")
   179  	}
   180  	return nil, 0, errors.New("insufficient bytes to decode value")
   181  }
   182  
   183  const (
   184  	negativeTagEnd   = 8        // negative tag is (negativeTagEnd - length).
   185  	positiveTagStart = 0xff - 8 // Positive tag is (positiveTagStart + length).
   186  )
   187  
   188  // EncodeComparableVarint encodes an int64 to a mem-comparable bytes.
   189  func EncodeComparableVarint(b []byte, v int64) []byte {
   190  	if v < 0 {
   191  		// All negative value has a tag byte prefix (negativeTagEnd - length).
   192  		// Smaller negative value encodes to more bytes, has smaller tag.
   193  		if v >= -0xff {
   194  			return append(b, negativeTagEnd-1, byte(v))
   195  		} else if v >= -0xffff {
   196  			return append(b, negativeTagEnd-2, byte(v>>8), byte(v))
   197  		} else if v >= -0xffffff {
   198  			return append(b, negativeTagEnd-3, byte(v>>16), byte(v>>8), byte(v))
   199  		} else if v >= -0xffffffff {
   200  			return append(b, negativeTagEnd-4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
   201  		} else if v >= -0xffffffffff {
   202  			return append(b, negativeTagEnd-5, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
   203  		} else if v >= -0xffffffffffff {
   204  			return append(b, negativeTagEnd-6, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8),
   205  				byte(v))
   206  		} else if v >= -0xffffffffffffff {
   207  			return append(b, negativeTagEnd-7, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16),
   208  				byte(v>>8), byte(v))
   209  		}
   210  		return append(b, negativeTagEnd-8, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24),
   211  			byte(v>>16), byte(v>>8), byte(v))
   212  	}
   213  	return EncodeComparableUvarint(b, uint64(v))
   214  }
   215  
   216  // EncodeComparableUvarint encodes uint64 into mem-comparable bytes.
   217  func EncodeComparableUvarint(b []byte, v uint64) []byte {
   218  	// The first byte has 256 values, [0, 7] is reserved for negative tags,
   219  	// [248, 255] is reserved for larger positive tags,
   220  	// So we can store value [0, 239] in a single byte.
   221  	// Values cannot be stored in single byte has a tag byte prefix (positiveTagStart+length).
   222  	// Larger value encodes to more bytes, has larger tag.
   223  	if v <= positiveTagStart-negativeTagEnd {
   224  		return append(b, byte(v)+negativeTagEnd)
   225  	} else if v <= 0xff {
   226  		return append(b, positiveTagStart+1, byte(v))
   227  	} else if v <= 0xffff {
   228  		return append(b, positiveTagStart+2, byte(v>>8), byte(v))
   229  	} else if v <= 0xffffff {
   230  		return append(b, positiveTagStart+3, byte(v>>16), byte(v>>8), byte(v))
   231  	} else if v <= 0xffffffff {
   232  		return append(b, positiveTagStart+4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
   233  	} else if v <= 0xffffffffff {
   234  		return append(b, positiveTagStart+5, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
   235  	} else if v <= 0xffffffffffff {
   236  		return append(b, positiveTagStart+6, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8),
   237  			byte(v))
   238  	} else if v <= 0xffffffffffffff {
   239  		return append(b, positiveTagStart+7, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16),
   240  			byte(v>>8), byte(v))
   241  	}
   242  	return append(b, positiveTagStart+8, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24),
   243  		byte(v>>16), byte(v>>8), byte(v))
   244  }
   245  
   246  var (
   247  	errDecodeInsufficient = errors.New("insufficient bytes to decode value")
   248  	errDecodeInvalid      = errors.New("invalid bytes to decode value")
   249  )
   250  
   251  // DecodeComparableUvarint decodes mem-comparable uvarint.
   252  func DecodeComparableUvarint(b []byte) ([]byte, uint64, error) {
   253  	if len(b) == 0 {
   254  		return nil, 0, errDecodeInsufficient
   255  	}
   256  	first := b[0]
   257  	b = b[1:]
   258  	if first < negativeTagEnd {
   259  		return nil, 0, errors.Trace(errDecodeInvalid)
   260  	}
   261  	if first <= positiveTagStart {
   262  		return b, uint64(first) - negativeTagEnd, nil
   263  	}
   264  	length := int(first) - positiveTagStart
   265  	if len(b) < length {
   266  		return nil, 0, errors.Trace(errDecodeInsufficient)
   267  	}
   268  	var v uint64
   269  	for _, c := range b[:length] {
   270  		v = (v << 8) | uint64(c)
   271  	}
   272  	return b[length:], v, nil
   273  }
   274  
   275  // DecodeComparableVarint decodes mem-comparable varint.
   276  func DecodeComparableVarint(b []byte) ([]byte, int64, error) {
   277  	if len(b) == 0 {
   278  		return nil, 0, errors.Trace(errDecodeInsufficient)
   279  	}
   280  	first := b[0]
   281  	if first >= negativeTagEnd && first <= positiveTagStart {
   282  		return b, int64(first) - negativeTagEnd, nil
   283  	}
   284  	b = b[1:]
   285  	var length int
   286  	var v uint64
   287  	if first < negativeTagEnd {
   288  		length = negativeTagEnd - int(first)
   289  		v = math.MaxUint64 // negative value has all bits on by default.
   290  	} else {
   291  		length = int(first) - positiveTagStart
   292  	}
   293  	if len(b) < length {
   294  		return nil, 0, errors.Trace(errDecodeInsufficient)
   295  	}
   296  	for _, c := range b[:length] {
   297  		v = (v << 8) | uint64(c)
   298  	}
   299  	if first > positiveTagStart && v > math.MaxInt64 {
   300  		return nil, 0, errors.Trace(errDecodeInvalid)
   301  	} else if first < negativeTagEnd && v <= math.MaxInt64 {
   302  		return nil, 0, errors.Trace(errDecodeInvalid)
   303  	}
   304  	return b[length:], int64(v), nil
   305  }