| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package influxdbsubscribe
- import (
- "bytes"
- "fmt"
- "math"
- "reflect"
- "strconv"
- "strings"
- "time"
- "unsafe"
- )
- var (
- Codes = map[byte][]byte{
- ',': []byte(`\,`),
- '"': []byte(`\"`),
- ' ': []byte(`\ `),
- '=': []byte(`\=`),
- }
- codesStr = map[string]string{}
- )
- func init() {
- for k, v := range Codes {
- codesStr[string(k)] = string(v)
- }
- }
- const (
- // MinNanoTime is the minumum time that can be represented.
- //
- // 1677-09-21 00:12:43.145224194 +0000 UTC
- //
- // The two lowest minimum integers are used as sentinel values. The
- // minimum value needs to be used as a value lower than any other value for
- // comparisons and another separate value is needed to act as a sentinel
- // default value that is unusable by the user, but usable internally.
- // Because these two values need to be used for a special purpose, we do
- // not allow users to write points at these two times.
- MinNanoTime = int64(math.MinInt64) + 2
- // MaxNanoTime is the maximum time that can be represented.
- //
- // 2262-04-11 23:47:16.854775806 +0000 UTC
- //
- // The highest time represented by a nanosecond needs to be used for an
- // exclusive range in the shard group, so the maximum time needs to be one
- // less than the possible maximum number of nanoseconds representable by an
- // int64 so that we don't lose a point at that one time.
- MaxNanoTime = int64(math.MaxInt64) - 1
- )
- var (
- minNanoTime = time.Unix(0, MinNanoTime).UTC()
- maxNanoTime = time.Unix(0, MaxNanoTime).UTC()
- // ErrTimeOutOfRange gets returned when time is out of the representable range using int64 nanoseconds since the epoch.
- ErrTimeOutOfRange = fmt.Errorf("time outside range %d - %d", MinNanoTime, MaxNanoTime)
- )
- // parseIntBytes is a zero-alloc wrapper around strconv.ParseInt.
- func parseIntBytes(b []byte, base int, bitSize int) (i int64, err error) {
- s := unsafeBytesToString(b)
- return strconv.ParseInt(s, base, bitSize)
- }
- // unsafeBytesToString converts a []byte to a string without a heap allocation.
- //
- // It is unsafe, and is intended to prepare input to short-lived functions
- // that require strings.
- func unsafeBytesToString(in []byte) string {
- src := *(*reflect.SliceHeader)(unsafe.Pointer(&in))
- dst := reflect.StringHeader{
- Data: src.Data,
- Len: src.Len,
- }
- s := *(*string)(unsafe.Pointer(&dst))
- return s
- }
- // parseFloatBytes is a zero-alloc wrapper around strconv.ParseFloat.
- func parseFloatBytes(b []byte, bitSize int) (float64, error) {
- s := unsafeBytesToString(b)
- return strconv.ParseFloat(s, bitSize)
- }
- // parseBoolBytes is a zero-alloc wrapper around strconv.ParseBool.
- func parseBoolBytes(b []byte) (bool, error) {
- return strconv.ParseBool(unsafeBytesToString(b))
- }
- func Unescape(in []byte) []byte {
- if len(in) == 0 {
- return nil
- }
- if bytes.IndexByte(in, '\\') == -1 {
- return in
- }
- i := 0
- inLen := len(in)
- var out []byte
- for {
- if i >= inLen {
- break
- }
- if in[i] == '\\' && i+1 < inLen {
- switch in[i+1] {
- case ',':
- out = append(out, ',')
- i += 2
- continue
- case '"':
- out = append(out, '"')
- i += 2
- continue
- case ' ':
- out = append(out, ' ')
- i += 2
- continue
- case '=':
- out = append(out, '=')
- i += 2
- continue
- }
- }
- out = append(out, in[i])
- i += 1
- }
- return out
- }
- func UnescapeString(in string) string {
- if strings.IndexByte(in, '\\') == -1 {
- return in
- }
- for b, esc := range codesStr {
- in = strings.Replace(in, esc, b, -1)
- }
- return in
- }
- func GetString(in string) string {
- for b, esc := range codesStr {
- in = strings.Replace(in, b, esc, -1)
- }
- return in
- }
- // SafeCalcTime safely calculates the time given. Will return error if the time is outside the
- // supported range.
- func SafeCalcTime(timestamp int64, precision string) (time.Time, error) {
- mult := GetPrecisionMultiplier(precision)
- if t, ok := safeSignedMult(timestamp, mult); ok {
- tme := time.Unix(0, t).UTC()
- return tme, CheckTime(tme)
- }
- return time.Time{}, ErrTimeOutOfRange
- }
- // CheckTime checks that a time is within the safe range.
- func CheckTime(t time.Time) error {
- if t.Before(minNanoTime) || t.After(maxNanoTime) {
- return ErrTimeOutOfRange
- }
- return nil
- }
- // Perform the multiplication and check to make sure it didn't overflow.
- func safeSignedMult(a, b int64) (int64, bool) {
- if a == 0 || b == 0 || a == 1 || b == 1 {
- return a * b, true
- }
- if a == MinNanoTime || b == MaxNanoTime {
- return 0, false
- }
- c := a * b
- return c, c/b == a
- }
- const escapeChars = `," =`
- func IsEscaped(b []byte) bool {
- for len(b) > 0 {
- i := bytes.IndexByte(b, '\\')
- if i < 0 {
- return false
- }
- if i+1 < len(b) && strings.IndexByte(escapeChars, b[i+1]) >= 0 {
- return true
- }
- b = b[i+1:]
- }
- return false
- }
- func AppendUnescaped(dst, src []byte) []byte {
- var pos int
- for len(src) > 0 {
- next := bytes.IndexByte(src[pos:], '\\')
- if next < 0 || pos+next+1 >= len(src) {
- return append(dst, src...)
- }
- if pos+next+1 < len(src) && strings.IndexByte(escapeChars, src[pos+next+1]) >= 0 {
- if pos+next > 0 {
- dst = append(dst, src[:pos+next]...)
- }
- src = src[pos+next+1:]
- pos = 0
- } else {
- pos += next + 1
- }
- }
- return dst
- }
|