github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/mysql/bit.go (about) 1 // Copyright 2015 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package mysql 15 16 import ( 17 "fmt" 18 "strconv" 19 "strings" 20 21 "github.com/insionng/yougam/libraries/juju/errors" 22 ) 23 24 // Bit is for mysql bit type. 25 type Bit struct { 26 // Value holds the value for bit type. 27 Value uint64 28 29 // Width is the display with for bit value. 30 // e.g, with is 8, 0 is for 0b00000000. 31 Width int 32 } 33 34 // String implements fmt.Stringer interface. 35 func (b Bit) String() string { 36 format := fmt.Sprintf("0b%%0%db", b.Width) 37 return fmt.Sprintf(format, b.Value) 38 } 39 40 // ToNumber changes bit type to float64 for numeric operation. 41 // MySQL treats bit as double type. 42 func (b Bit) ToNumber() float64 { 43 return float64(b.Value) 44 } 45 46 // ToString returns the binary string for bit type. 47 func (b Bit) ToString() string { 48 byteSize := (b.Width + 7) / 8 49 buf := make([]byte, byteSize) 50 for i := byteSize - 1; i >= 0; i-- { 51 buf[byteSize-i-1] = byte(b.Value >> uint(i*8)) 52 } 53 return string(buf) 54 } 55 56 // Min and Max bit width. 57 const ( 58 MinBitWidth = 1 59 MaxBitWidth = 64 60 // UnspecifiedBitWidth is the unspecified with if you want to calculate bit width dynamically. 61 UnspecifiedBitWidth = -1 62 ) 63 64 // ParseBit parses bit string. 65 // The string format can be b'val', B'val' or 0bval, val must be 0 or 1. 66 // Width is the display width for bit representation. -1 means calculating 67 // width dynamically, using following algorithm: (len("011101") + 7) & ^7, 68 // e.g, if bit string is 0b01, the above will return 8 for its bit width. 69 func ParseBit(s string, width int) (Bit, error) { 70 if len(s) == 0 { 71 return Bit{}, errors.Errorf("invalid empty string for parsing bit type") 72 } 73 74 if s[0] == 'b' || s[0] == 'B' { 75 // format is b'val' or B'val' 76 s = strings.Trim(s[1:], "'") 77 } else if strings.HasPrefix(s, "0b") { 78 s = s[2:] 79 } else { 80 // here means format is not b'val', B'val' or 0bval. 81 return Bit{}, errors.Errorf("invalid bit type format %s", s) 82 } 83 84 if width == UnspecifiedBitWidth { 85 width = (len(s) + 7) & ^7 86 } 87 88 if width == 0 { 89 width = MinBitWidth 90 } 91 92 if width < MinBitWidth || width > MaxBitWidth { 93 return Bit{}, errors.Errorf("invalid display width for bit type, must in [1, 64], but %d", width) 94 } 95 96 n, err := strconv.ParseUint(s, 2, 64) 97 if err != nil { 98 return Bit{}, errors.Trace(err) 99 } 100 101 if n > (uint64(1)<<uint64(width))-1 { 102 return Bit{}, errors.Errorf("bit %s is too long for width %d", s, width) 103 } 104 105 return Bit{Value: n, Width: width}, nil 106 }