1 // Copyright 2016 The Cockroach 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 12 // implied. See the License for the specific language governing 13 // permissions and limitations under the License. 14 15 package apd 16 17 import "fmt" 18 19 // decomposer composes or decomposes a decimal value to and from individual parts. 20 // There are four separate parts: a boolean negative flag, a form byte with three possible states 21 // (finite=0, infinite=1, NaN=2), a base-2 big-endian integer 22 // coefficient (also known as a significand) as a []byte, and an int32 exponent. 23 // These are composed into a final value as "decimal = (neg) (form=finite) coefficient * 10 ^ exponent". 24 // A zero length coefficient is a zero value. 25 // If the form is not finite the coefficient and scale should be ignored. 26 // The negative parameter may be set to true for any form, although implementations are not required 27 // to respect the negative parameter in the non-finite form. 28 // 29 // Implementations may choose to signal a negative zero or negative NaN, but implementations 30 // that do not support these may also ignore the negative zero or negative NaN without error. 31 // If an implementation does not support Infinity it may be converted into a NaN without error. 32 // If a value is set that is larger then what is supported by an implementation is attempted to 33 // be set, an error must be returned. 34 // Implementations must return an error if a NaN or Infinity is attempted to be set while neither 35 // are supported. 36 type decomposer interface { 37 // Decompose returns the internal decimal state into parts. 38 // If the provided buf has sufficient capacity, buf may be returned as the coefficient with 39 // the value set and length set as appropriate. 40 Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) 41 42 // Compose sets the internal decimal value from parts. If the value cannot be 43 // represented then an error should be returned. 44 // The coefficent should not be modified. Successive calls to compose with 45 // the same arguments should result in the same decimal value. 46 Compose(form byte, negative bool, coefficient []byte, exponent int32) error 47 } 48 49 var _ decomposer = &Decimal{} 50 51 // Decompose returns the internal decimal state into parts. 52 // If the provided buf has sufficient capacity, buf may be returned as the coefficient with 53 // the value set and length set as appropriate. 54 func (d *Decimal) Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) { 55 switch d.Form { 56 default: 57 panic(fmt.Errorf("unknown Form: %v", d.Form)) 58 case Finite: 59 // Nothing, continue on. 60 case Infinite: 61 negative = d.Negative 62 form = 1 63 return 64 case NaNSignaling, NaN: 65 negative = d.Negative 66 form = 2 67 return 68 } 69 // Finite form. 70 negative = d.Negative 71 exponent = d.Exponent 72 coefficient = d.Coeff.Bytes() 73 return 74 } 75 76 // Compose sets the internal decimal value from parts. If the value cannot be 77 // represented then an error should be returned. 78 func (d *Decimal) Compose(form byte, negative bool, coefficient []byte, exponent int32) error { 79 switch form { 80 default: 81 return fmt.Errorf("unknown form: %v", form) 82 case 0: 83 d.Form = Finite 84 // Set rest of finite form below. 85 case 1: 86 d.Form = Infinite 87 d.Negative = negative 88 return nil 89 case 2: 90 d.Form = NaN 91 d.Negative = negative 92 return nil 93 } 94 // Finite form. 95 d.Negative = negative 96 d.Coeff.SetBytes(coefficient) 97 d.Exponent = exponent 98 return nil 99 } 100