github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/encoding/proto/int_encoder_iterator.go (about)

     1  // Copyright (c) 2019 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package proto
    22  
    23  import (
    24  	"fmt"
    25  
    26  	"github.com/m3db/m3/src/dbnode/encoding"
    27  	"github.com/m3db/m3/src/dbnode/encoding/m3tsz"
    28  )
    29  
    30  type intEncoderAndIterator struct {
    31  	prevIntBits       uint64
    32  	intSigBitsTracker m3tsz.IntSigBitsTracker
    33  	unsigned          bool
    34  	hasEncodedFirst   bool
    35  }
    36  
    37  func (eit *intEncoderAndIterator) encodeSignedIntValue(stream encoding.OStream, v int64) {
    38  	if eit.hasEncodedFirst {
    39  		eit.encodeNextSignedIntValue(stream, v)
    40  	} else {
    41  		eit.encodeFirstSignedIntValue(stream, v)
    42  		eit.hasEncodedFirst = true
    43  	}
    44  }
    45  
    46  func (eit *intEncoderAndIterator) encodeUnsignedIntValue(stream encoding.OStream, v uint64) {
    47  	if eit.hasEncodedFirst {
    48  		eit.encodeNextUnsignedIntValue(stream, v)
    49  	} else {
    50  		eit.encodeFirstUnsignedIntValue(stream, v)
    51  		eit.hasEncodedFirst = true
    52  	}
    53  }
    54  
    55  func (eit *intEncoderAndIterator) encodeFirstSignedIntValue(stream encoding.OStream, v int64) {
    56  	neg := false
    57  	eit.prevIntBits = uint64(v)
    58  	if v < 0 {
    59  		neg = true
    60  		v = -1 * v
    61  	}
    62  
    63  	vBits := uint64(v)
    64  	numSig := encoding.NumSig(vBits)
    65  
    66  	eit.intSigBitsTracker.WriteIntSig(stream, numSig)
    67  	eit.encodeIntValDiff(stream, vBits, neg, numSig)
    68  }
    69  
    70  func (eit *intEncoderAndIterator) encodeFirstUnsignedIntValue(stream encoding.OStream, v uint64) {
    71  	eit.prevIntBits = v
    72  
    73  	numSig := encoding.NumSig(v)
    74  	eit.intSigBitsTracker.WriteIntSig(stream, numSig)
    75  	eit.encodeIntValDiff(stream, v, false, numSig)
    76  }
    77  
    78  func (eit *intEncoderAndIterator) encodeNextSignedIntValue(stream encoding.OStream, next int64) {
    79  	prev := int64(eit.prevIntBits)
    80  	diff := next - prev
    81  	if diff == 0 {
    82  		stream.WriteBit(opCodeNoChange)
    83  		return
    84  	}
    85  
    86  	stream.WriteBit(opCodeChange)
    87  
    88  	neg := false
    89  	if diff < 0 {
    90  		neg = true
    91  		diff = -1 * diff
    92  	}
    93  
    94  	var (
    95  		diffBits = uint64(diff)
    96  		numSig   = encoding.NumSig(diffBits)
    97  		newSig   = eit.intSigBitsTracker.TrackNewSig(numSig)
    98  	)
    99  
   100  	eit.intSigBitsTracker.WriteIntSig(stream, newSig)
   101  	eit.encodeIntValDiff(stream, diffBits, neg, newSig)
   102  	eit.prevIntBits = uint64(next)
   103  }
   104  
   105  func (eit *intEncoderAndIterator) encodeNextUnsignedIntValue(stream encoding.OStream, next uint64) {
   106  	var (
   107  		neg  = false
   108  		prev = eit.prevIntBits
   109  		diff uint64
   110  	)
   111  
   112  	// Avoid overflows.
   113  	if next > prev {
   114  		diff = next - prev
   115  	} else {
   116  		neg = true
   117  		diff = prev - next
   118  	}
   119  
   120  	if diff == 0 {
   121  		stream.WriteBit(opCodeNoChange)
   122  		return
   123  	}
   124  
   125  	stream.WriteBit(opCodeChange)
   126  
   127  	numSig := encoding.NumSig(diff)
   128  	newSig := eit.intSigBitsTracker.TrackNewSig(numSig)
   129  
   130  	eit.intSigBitsTracker.WriteIntSig(stream, newSig)
   131  	eit.encodeIntValDiff(stream, diff, neg, newSig)
   132  	eit.prevIntBits = next
   133  }
   134  
   135  func (eit *intEncoderAndIterator) encodeIntValDiff(stream encoding.OStream, valBits uint64, neg bool, numSig uint8) {
   136  	if neg {
   137  		// opCodeNegative
   138  		stream.WriteBit(opCodeIntDeltaNegative)
   139  	} else {
   140  		// opCodePositive
   141  		stream.WriteBit(opCodeIntDeltaPositive)
   142  	}
   143  
   144  	stream.WriteBits(valBits, int(numSig))
   145  }
   146  
   147  func (eit *intEncoderAndIterator) readIntValue(stream *encoding.IStream) error {
   148  	if eit.hasEncodedFirst {
   149  		changeExistsControlBit, err := stream.ReadBit()
   150  		if err != nil {
   151  			return fmt.Errorf(
   152  				"%s: error trying to read int change exists control bit: %v",
   153  				itErrPrefix, err)
   154  		}
   155  
   156  		if changeExistsControlBit == opCodeNoChange {
   157  			// No change.
   158  			return nil
   159  		}
   160  	}
   161  
   162  	if err := eit.readIntSig(stream); err != nil {
   163  		return fmt.Errorf(
   164  			"%s error trying to read number of significant digits: %v",
   165  			itErrPrefix, err)
   166  	}
   167  
   168  	if err := eit.readIntValDiff(stream); err != nil {
   169  		return fmt.Errorf(
   170  			"%s error trying to read int diff: %v",
   171  			itErrPrefix, err)
   172  	}
   173  
   174  	if !eit.hasEncodedFirst {
   175  		eit.hasEncodedFirst = true
   176  	}
   177  
   178  	return nil
   179  }
   180  
   181  func (eit *intEncoderAndIterator) readIntSig(stream *encoding.IStream) error {
   182  	updateControlBit, err := stream.ReadBit()
   183  	if err != nil {
   184  		return fmt.Errorf(
   185  			"%s error reading int significant digits update control bit: %v",
   186  			itErrPrefix, err)
   187  	}
   188  	if updateControlBit == opCodeNoChange {
   189  		// No change.
   190  		return nil
   191  	}
   192  
   193  	sigDigitsControlBit, err := stream.ReadBit()
   194  	if err != nil {
   195  		return fmt.Errorf(
   196  			"%s error reading zero significant digits control bit: %v",
   197  			itErrPrefix, err)
   198  	}
   199  	if sigDigitsControlBit == m3tsz.OpcodeZeroSig {
   200  		eit.intSigBitsTracker.NumSig = 0
   201  	} else {
   202  		numSigBits, err := stream.ReadBits(6)
   203  		if err != nil {
   204  			return fmt.Errorf(
   205  				"%s error reading number of significant digits: %v",
   206  				itErrPrefix, err)
   207  		}
   208  
   209  		eit.intSigBitsTracker.NumSig = uint8(numSigBits) + 1
   210  	}
   211  
   212  	return nil
   213  }
   214  
   215  func (eit *intEncoderAndIterator) readIntValDiff(stream *encoding.IStream) error {
   216  	negativeControlBit, err := stream.ReadBit()
   217  	if err != nil {
   218  		return fmt.Errorf(
   219  			"%s error reading negative control bit: %v",
   220  			itErrPrefix, err)
   221  	}
   222  
   223  	numSig := eit.intSigBitsTracker.NumSig
   224  	diffSigBits, err := stream.ReadBits(numSig)
   225  	if err != nil {
   226  		return fmt.Errorf(
   227  			"%s error reading significant digits: %v",
   228  			itErrPrefix, err)
   229  	}
   230  
   231  	if eit.unsigned {
   232  		diff := diffSigBits
   233  		shouldSubtract := false
   234  		if negativeControlBit == opCodeIntDeltaNegative {
   235  			shouldSubtract = true
   236  		}
   237  
   238  		prev := eit.prevIntBits
   239  		if shouldSubtract {
   240  			eit.prevIntBits = prev - diff
   241  		} else {
   242  			eit.prevIntBits = prev + diff
   243  		}
   244  	} else {
   245  		diff := int64(diffSigBits)
   246  		sign := int64(1)
   247  		if negativeControlBit == opCodeIntDeltaNegative {
   248  			sign = -1.0
   249  		}
   250  
   251  		prev := int64(eit.prevIntBits)
   252  		eit.prevIntBits = uint64(prev + (sign * diff))
   253  	}
   254  
   255  	return nil
   256  }