github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/codec/number.go (about)

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