func decodeNonsortingDecimalValueWithoutExp(dec *inf.Dec, buf, tmp []byte) { bi := dec.UnscaledBig() bi.SetBytes(buf) // Set the decimal's scale. nDigits, _ := decimal.NumDigits(bi, tmp) dec.SetScale(inf.Scale(nDigits)) }
func decodeNonsortingDecimalValue(dec *inf.Dec, negExp bool, buf, tmp []byte) error { // Decode the exponent. buf, e, err := DecodeUvarintAscending(buf) if err != nil { return err } if negExp { e = -e } bi := dec.UnscaledBig() bi.SetBytes(buf) // Set the decimal's scale. nDigits, _ := decimal.NumDigits(bi, tmp) exp := int(e) - nDigits dec.SetScale(inf.Scale(-exp)) return nil }
// EncodeNonsortingDecimal returns the resulting byte slice with the // encoded decimal appended to b. The encoding is limited compared to // standard encodings in this package in that // - It will not sort lexicographically // - It does not encode its length or terminate itself, so decoding // functions must be provided the exact encoded bytes // // The encoding assumes that any number can be written as ±0.xyz... * 10^exp, // where xyz is a digit string, x != 0, and the last decimal in xyz is also // not 0. // // The encoding uses its first byte to split decimals into 7 distinct // ordered groups (no NaN or Infinity support yet). The groups can // be seen in encoding.go's const definition. Following this, the // absolute value of the exponent of the decimal (as defined above) // is encoded as an unsigned varint. Second, the absolute value of // the digit string is added as a big-endian byte slice. // // All together, the encoding looks like: // <marker><uvarint exponent><big-endian encoded big.Int>. // // The markers are shared with the sorting decimal encoding as follows: // decimalNaN -> decimalNaN // decimalNegativeInfinity -> decimalNegativeInfinity // decimalNegLarge -> decimalNegValPosExp // decimalNegMedium -> decimalNegValZeroExp // decimalNegSmall -> decimalNegValNegExp // decimalZero -> decimalZero // decimalPosSmall -> decimalPosValNegExp // decimalPosMedium -> decimalPosValZeroExp // decimalPosLarge -> decimalPosValPosExp // decimalInfinity -> decimalInfinity // decimalNaNDesc -> decimalNaNDesc // func EncodeNonsortingDecimal(b []byte, d *inf.Dec) []byte { tmp := b[len(b):] neg := false bi := d.UnscaledBig() switch bi.Sign() { case -1: neg = true // Make a deep copy of the decimal's big.Int by calling Neg. // We shouldn't be modifying the provided argument's // internal big.Int, so this works like a copy-on-write scheme. bi = new(big.Int) bi = bi.Neg(d.UnscaledBig()) case 0: return append(b, decimalZero) } // Determine the exponent of the decimal, with the // exponent defined as .xyz * 10^exp. nDigits, formatted := decimal.NumDigits(bi, tmp) e := nDigits - int(d.Scale()) // Handle big.Int having zeros at the end of its // string by dividing them off (ie. 12300 -> 123). bi = normalizeBigInt(bi, bi == d.UnscaledBig(), formatted, tmp) bNat := bi.Bits() var buf []byte if n := UpperBoundNonsortingDecimalSize(d); n <= cap(b)-len(b) { // We append the marker directly to the input buffer b below, so // we are off by 1 for each of these, which explains the adjustments. buf = b[len(b)+1 : len(b)+1] } else { buf = make([]byte, 0, n-1) } switch { case neg && e > 0: b = append(b, decimalNegLarge) buf = encodeNonsortingDecimalValue(uint64(e), bNat, buf) return append(b, buf...) case neg && e == 0: b = append(b, decimalNegMedium) buf = encodeNonsortingDecimalValueWithoutExp(bNat, buf) return append(b, buf...) case neg && e < 0: b = append(b, decimalNegSmall) buf = encodeNonsortingDecimalValue(uint64(-e), bNat, buf) return append(b, buf...) case !neg && e < 0: b = append(b, decimalPosSmall) buf = encodeNonsortingDecimalValue(uint64(-e), bNat, buf) return append(b, buf...) case !neg && e == 0: b = append(b, decimalPosMedium) buf = encodeNonsortingDecimalValueWithoutExp(bNat, buf) return append(b, buf...) case !neg && e > 0: b = append(b, decimalPosLarge) buf = encodeNonsortingDecimalValue(uint64(e), bNat, buf) return append(b, buf...) } panic("unreachable") }