package bin import ( "errors" "fmt" "io" "math" ) // ByteOrder - порядок байт type ByteOrder string const ( // LH - low to high byte order LH ByteOrder = "LH" // HL - high to low byte order HL ByteOrder = "HL" // Int32SignBit uint32 = 1 << 31 // Int64SignBit uint64 = 1 << 63 maxReadAttempts = 5 ) var ( // ErrReadOverflow shows 100% bug in the source reader ErrReadOverflow = errors.New("bin: reader returned 'n' > bufsize") // ErrNegativeReadCount shows 100% bug in the source reader ErrNegativeReadCount = errors.New("bin: reader returned negative 'n'") ) // ReadN - безопасно читаем n байт. Обрабатывает все возможные ситуации, в том числе // баги Reader func ReadN(r io.Reader, n int) (_ []byte, err error) { if n < 0 { err = fmt.Errorf("wrong n=%d", n) return } buf := make([]byte, n) err = ReadNInto(r, buf) if err != nil { return } return buf, nil } func ReadNInto(r io.Reader, buf []byte) (err error) { if len(buf) == 0 { return } var q, total, readAttempts int // Избегаем вечного цикла из-за неправильной реализации ридера for readAttempts < maxReadAttempts { bufsize := len(buf) - total q, err = r.Read(buf[total:]) // Если буфер заполнен - успех, err игнорируем if q == bufsize { return nil } // Если ошибка - выходим с ошибкой if err != nil { return } // Если прочитали больше чем размер буфера. Баг в Reader if q > bufsize { err = ErrReadOverflow return } // Если прочитали < 0. Баг в Reader if q < 0 { err = ErrNegativeReadCount return } // Если ошибки нет, а прочитали 0 байт - чтобы не войти в бесконечный цикл // увеличиваем readAttempts if q == 0 { readAttempts++ } else { // Что-то прочитали, но меньше чем нужно - увеличиваем счетчик // суммарно прочитанного total += q } } err = io.ErrNoProgress return } // var zeroUnixTime = []byte{0, 0, 0, 0, 0, 0} // func Read6bDateTime(r io.ByteReader) (_ time.Time, err error) { // var arr []byte // for i := 0; i < 6; i++ { // var b byte // b, err = r.ReadByte() // if err != nil { // return // } // arr = append(arr, b) // } // if bytes.Equal(arr, zeroUnixTime) { // return time.Unix(0, 0), nil // } // tm := time.Date( // int(arr[0])+2000, // time.Month(arr[1]), // int(arr[2]), // int(arr[3]), // int(arr[4]), // int(arr[5]), // 0, // time.UTC, // ) // return tm, nil // } // func Write6bDateTime(w io.Writer, tm time.Time) (err error) { // var arr []byte // // ВАЖНО! // tm = tm.In(time.UTC) // if tm.Unix() == 0 { // arr = zeroUnixTime // } else { // arr = []byte{ // byte(tm.Year() - 2000), // byte(tm.Month()), // byte(tm.Day()), // byte(tm.Hour()), // byte(tm.Minute()), // byte(tm.Second()), // } // } // _, err = w.Write(arr) // return // } const ( MaxUint8 uint64 = 1<<8 - 1 MaxUint16 uint64 = 1<<16 - 1 MaxUint24 uint64 = 1<<24 - 1 MaxUint32 uint64 = 1<<32 - 1 MaxUint40 uint64 = 1<<40 - 1 MaxUint48 uint64 = 1<<48 - 1 MaxUint56 uint64 = 1<<56 - 1 MaxUint64 uint64 = 18446744073709551615 // MaxSafeInt - максимальное целое, которое можно сохранить в переменной // типа float64 без потери точности MinSafeInt int64 = -(1 << 53) MaxSafeInt int64 = 1<<53 - 1 ) // WriteMaxSafeUint - кодирует 2**53-1 // LH func WriteMaxSafeUint(w io.Writer, num uint64, byteOrder ByteOrder) (n int, err error) { var arr []byte if num <= MaxUint8 { arr = []byte{ byte(num), } } else if num <= MaxUint16 { if byteOrder == LH { arr = []byte{ byte(num), byte(num >> 8), } } else { arr = []byte{ byte(num >> 8), byte(num), } } } else if num <= MaxUint24 { if byteOrder == LH { arr = []byte{ byte(num), byte(num >> 8), byte(num >> 16), } } else { arr = []byte{ byte(num >> 16), byte(num >> 8), byte(num), } } } else if num <= MaxUint32 { if byteOrder == LH { arr = []byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), } } else { arr = []byte{ byte(num >> 24), byte(num >> 16), byte(num >> 8), byte(num), } } } else if num <= MaxUint40 { if byteOrder == LH { arr = []byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), byte(num >> 32), } } else { arr = []byte{ byte(num >> 32), byte(num >> 24), byte(num >> 16), byte(num >> 8), byte(num), } } } else if num <= MaxUint48 { if byteOrder == LH { arr = []byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), byte(num >> 32), byte(num >> 40), } } else { arr = []byte{ byte(num >> 40), byte(num >> 32), byte(num >> 24), byte(num >> 16), byte(num >> 8), byte(num), } } } else if num <= uint64(MaxSafeInt) { if byteOrder == LH { arr = []byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), byte(num >> 32), byte(num >> 40), byte(num >> 48), } } else { arr = []byte{ byte(num >> 48), byte(num >> 40), byte(num >> 32), byte(num >> 24), byte(num >> 16), byte(num >> 8), byte(num), } } } else { err = fmt.Errorf("num %d > MaxSafeInt %d", num, MaxSafeInt) return } return w.Write(arr) } type SplittedFloat struct { Int int64 // bin.MaxSafeInt Frac int64 // до 7 разрядов } func (s SplittedFloat) AsFloat64(fracDigits int) float64 { //return float64(s.Int) + float64(s.Frac)/ fracMultipliers[fracDigits] return float64(s.Int) + float64(s.Frac)/math.Pow10(fracDigits) } /* var fracMultipliers = []float64{ 0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, } */ var prec = []float64{ 0.999999999, // 0 0.99999999, // 1 0.9999999, // 2 0.999999, // 3 0.99999, // 4 0.9999, // 5 0.999, // 6 0.99, // 7 //0.99, // 8 } func SplitFloat(num float64, fracDigits int) SplittedFloat { var isNegative bool if num < 0 { isNegative = true } num = math.Abs(num) //if fracDigits >= len(fracMultipliers) { // panic(fmt.Sprintf("max fracDigits is %d, not %d\n", // len(fracMultipliers), fracDigits)) //} i, f := math.Modf(num) poweredFrac := f * math.Pow10(fracDigits) // В этот момент может произойти потеря точности, когда 0.55 превратится // в 0.5499999999 (в меньшую сторону) fracAsInt := int64(poweredFrac) // dif := poweredFrac - float64(fracAsInt) //fmt.Printf("DIF %.10f\n\n", dif) var eps float64 if fracDigits >= len(prec) { eps = 0.99 } else { eps = prec[fracDigits] } if dif > eps { fracAsInt++ } //fmt.Printf("\nSPLIT: %.10f, int = %d, frac = %v, %v, %d\n\n", num, int(i), f, f*fracMultipliers[fracDigits], int(f*fracMultipliers[fracDigits])) if isNegative { i *= -1 } return SplittedFloat{ Int: int64(i), Frac: fracAsInt, } } /* // Round a float to a specific decimal place or precision func Round(input float64, places int) (rounded float64, err error) { // If the float is not a number if math.IsNaN(input) { return math.NaN(), fmt.Errorf("fuck") } // Find out the actual sign and correct the input for later sign := 1.0 if input < 0 { sign = -1 input *= -1 } // Use the places arg to get the amount of precision wanted precision := math.Pow(10, float64(places)) // Find the decimal place we are looking to round digit := input * precision // Get the actual decimal number as a fraction to be compared _, decimal := math.Modf(digit) // If the decimal is less than .5 we round down otherwise up if decimal >= 0.5 { rounded = math.Ceil(digit) } else { rounded = math.Floor(digit) } // Finally we do the math to actually create a rounded number return rounded / precision * sign, nil } */ // FLAGS func IsSetFlag(flags byte, flag byte) bool { return (flags & flag) == flag } func SetFlag(flags byte, flag byte) byte { return flags | flag } func UnsetFlag(flags byte, flag byte) byte { return flags & ^flag } func UnsetBit(b byte, idx byte) byte { if ((b >> idx) & 1) == 1 { // сбрасываем var mask byte = ^(1 << idx) return b & mask } return b } func SetBit(b byte, idx byte) byte { if ((b >> idx) & 1) == 0 { // устанавливаем return b | (1 << idx) } return b }