func decodeTags(id []byte) map[string]string {
	a := bytes.Split(id, []byte{'\x00'})
	if len(a) > 0 && len(a)%2 == 1 {
		a = a[:len(a)-1]
	}
	if len(a) == 0 {
		return nil
	}
	mid := len(a) / 2
	m := make(map[string]string)
	for i := 0; i < mid; i++ {
		m[string(a[i])] = string(a[i+mid])
	}
	return m
}
decodeTags parses an identifier into a map of tags.
package query
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"math"
	"sort"
	"github.com/gogo/protobuf/proto"
	internal "github.com/influxdata/influxdb/query/internal"
	"github.com/influxdata/influxql"
)
const ZeroTime = int64(math.MinInt64)
type Point interface {
	name() string
	tags() Tags
	time() int64
	value() interface{}
	aux() []interface{}
}
type Points []Point
func (a Points) Clone() []Point {
	other := make([]Point, len(a))
	for i, p := range a {
		if p == nil {
			other[i] = nil
			continue
		}
		switch p := p.(type) {
		case *FloatPoint:
			other[i] = p.Clone()
		case *IntegerPoint:
			other[i] = p.Clone()
		case *UnsignedPoint:
			other[i] = p.Clone()
		case *StringPoint:
			other[i] = p.Clone()
		case *BooleanPoint:
			other[i] = p.Clone()
		default:
			panic(fmt.Sprintf("unable to clone point: %T", p))
		}
	}
	return other
}
type Tags struct {
	id string
	m  map[string]string
}
func NewTags(m map[string]string) Tags {
	if len(m) == 0 {
		return Tags{}
	}
	return Tags{
		id: string(encodeTags(m)),
		m:  m,
	}
}
func newTagsID(id string) Tags {
	m := decodeTags([]byte(id))
	if len(m) == 0 {
		return Tags{}
	}
	return Tags{id: id, m: m}
}
func (t Tags) Equal(other Tags) bool {
	return t.ID() == other.ID()
}
func (t Tags) ID() string { return t.id }
func (t Tags) KeyValues() map[string]string { return t.m }
func (t *Tags) Keys() []string {
	if t == nil {
		return nil
	}
	var a []string
	for k := range t.m {
		a = append(a, k)
	}
	sort.Strings(a)
	return a
}
func (t *Tags) Values() []string {
	if t == nil {
		return nil
	}
	a := make([]string, 0, len(t.m))
	for _, v := range t.m {
		a = append(a, v)
	}
	sort.Strings(a)
	return a
}
func (t *Tags) Value(k string) string {
	if t == nil {
		return ""
	}
	return t.m[k]
}
func (t *Tags) Subset(keys []string) Tags {
	if len(keys) == 0 {
		return Tags{}
	}
	if keysMatch(t.m, keys) {
		return *t
	}
	m := make(map[string]string, len(keys))
	for _, k := range keys {
		m[k] = t.m[k]
	}
	return NewTags(m)
}
func (t *Tags) Equals(other *Tags) bool {
	if t == nil && other == nil {
		return true
	} else if t == nil || other == nil {
		return false
	}
	return t.id == other.id
}
func keysMatch(m map[string]string, keys []string) bool {
	if len(keys) != len(m) {
		return false
	}
	for _, k := range keys {
		if _, ok := m[k]; !ok {
			return false
		}
	}
	return true
}
func encodeTags(m map[string]string) []byte {
	if len(m) == 0 {
		return nil
	}
	sz := (len(m) * 2) - 1  
	keys := make([]string, 0, len(m))
	for k, v := range m {
		keys = append(keys, k)
		sz += len(k) + len(v)
	}
	sort.Strings(keys)
	b := make([]byte, sz)
	buf := b
	for _, k := range keys {
		copy(buf, k)
		buf[len(k)] = '\x00'
		buf = buf[len(k)+1:]
	}
	for i, k := range keys {
		v := m[k]
		copy(buf, v)
		if i < len(keys)-1 {
			buf[len(v)] = '\x00'
			buf = buf[len(v)+1:]
		}
	}
	return b
}