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  }