github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/internal/base/comparer.go (about)

     1  // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors.
     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  package base
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/binary"
    20  	"fmt"
    21  	"strconv"
    22  	"unicode/utf8"
    23  )
    24  
    25  type Compare func(a, b []byte) int
    26  
    27  type Equal func(a, b []byte) bool
    28  
    29  type AbbreviatedKey func(key []byte) uint64
    30  
    31  type FormatKey func(key []byte) fmt.Formatter
    32  
    33  type FormatValue func(key, value []byte) fmt.Formatter
    34  
    35  type Separator func(dst, a, b []byte) []byte
    36  
    37  type Successor func(dst, a []byte) []byte
    38  
    39  type Split func(a []byte) int
    40  
    41  type Comparer struct {
    42  	Compare        Compare
    43  	Equal          Equal
    44  	AbbreviatedKey AbbreviatedKey
    45  	FormatKey      FormatKey
    46  	FormatValue    FormatValue
    47  	Separator      Separator
    48  	Split          Split
    49  	Successor      Successor
    50  	Name           string
    51  }
    52  
    53  var DefaultFormatter = func(key []byte) fmt.Formatter {
    54  	return FormatBytes(key)
    55  }
    56  
    57  var DefaultComparer = &Comparer{
    58  	Compare: bytes.Compare,
    59  	Equal:   bytes.Equal,
    60  
    61  	AbbreviatedKey: func(key []byte) uint64 {
    62  		if len(key) >= 8 {
    63  			return binary.BigEndian.Uint64(key)
    64  		}
    65  		var v uint64
    66  		for _, b := range key {
    67  			v <<= 8
    68  			v |= uint64(b)
    69  		}
    70  		return v << uint(8*(8-len(key)))
    71  	},
    72  
    73  	FormatKey: DefaultFormatter,
    74  
    75  	Separator: func(dst, a, b []byte) []byte {
    76  		i, n := SharedPrefixLen(a, b), len(dst)
    77  		dst = append(dst, a...)
    78  
    79  		min := len(a)
    80  		if min > len(b) {
    81  			min = len(b)
    82  		}
    83  		if i >= min {
    84  			return dst
    85  		}
    86  
    87  		if a[i] >= b[i] {
    88  			return dst
    89  		}
    90  
    91  		if i < len(b)-1 || a[i]+1 < b[i] {
    92  			i += n
    93  			dst[i]++
    94  			return dst[:i+1]
    95  		}
    96  
    97  		i += n + 1
    98  		for ; i < len(dst); i++ {
    99  			if dst[i] != 0xff {
   100  				dst[i]++
   101  				return dst[:i+1]
   102  			}
   103  		}
   104  		return dst
   105  	},
   106  
   107  	Successor: func(dst, a []byte) (ret []byte) {
   108  		for i := 0; i < len(a); i++ {
   109  			if a[i] != 0xff {
   110  				dst = append(dst, a[:i+1]...)
   111  				dst[len(dst)-1]++
   112  				return dst
   113  			}
   114  		}
   115  		return append(dst, a...)
   116  	},
   117  
   118  	Name: "bitalosdb.BytewiseComparator",
   119  }
   120  
   121  func SharedPrefixLen(a, b []byte) int {
   122  	i, n := 0, len(a)
   123  	if n > len(b) {
   124  		n = len(b)
   125  	}
   126  	asUint64 := func(c []byte, i int) uint64 {
   127  		return binary.LittleEndian.Uint64(c[i:])
   128  	}
   129  	for i < n-7 && asUint64(a, i) == asUint64(b, i) {
   130  		i += 8
   131  	}
   132  	for i < n && a[i] == b[i] {
   133  		i++
   134  	}
   135  	return i
   136  }
   137  
   138  type FormatBytes []byte
   139  
   140  const lowerhex = "0123456789abcdef"
   141  
   142  func (p FormatBytes) Format(s fmt.State, c rune) {
   143  	buf := make([]byte, 0, len(p))
   144  	for _, b := range p {
   145  		if b < utf8.RuneSelf && strconv.IsPrint(rune(b)) {
   146  			buf = append(buf, b)
   147  			continue
   148  		}
   149  		buf = append(buf, `\x`...)
   150  		buf = append(buf, lowerhex[b>>4])
   151  		buf = append(buf, lowerhex[b&0xF])
   152  	}
   153  	s.Write(buf)
   154  }