blob: d042f05e2d417ef758e99bad20e0f4103a333bf9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 thrift
import (
"container/list"
"reflect"
)
/**
* Helper class that encapsulates map metadata.
*
*/
type TMap interface {
KeyType() TType
ValueType() TType
Len() int
Set(key, value interface{})
Get(key interface{}) (interface{}, bool)
Contains(key interface{}) bool
Iter() <-chan TMapElem
KeyIter() <-chan interface{}
ValueIter() <-chan interface{}
Keys() []interface{}
Values() []interface{}
Less(other interface{}) bool
Equals(other interface{}) bool
CompareTo(other interface{}) (int, bool)
}
type TMapElem interface {
Key() interface{}
Value() interface{}
}
type tMap struct {
keyType TType
valueType TType
size int
l *list.List
b map[bool]interface{}
i08 map[byte]interface{}
i16 map[int16]interface{}
i32 map[int32]interface{}
i64 map[int64]interface{}
f64 map[float64]interface{}
s map[string]interface{}
}
type tMapElem struct {
key interface{}
value interface{}
}
func (p *tMapElem) Key() interface{} {
return p.key
}
func (p *tMapElem) Value() interface{} {
return p.value
}
func NewTMapElem(k, v interface{}) TMapElem {
return &tMapElem{key: k, value: v}
}
func NewTMap(k, v TType, s int) TMap {
return &tMap{keyType: k, valueType: v, size: s, l: list.New()}
}
func NewTMapDefault() TMap {
return NewTMap(STOP, STOP, 0)
}
func (p *tMap) KeyType() TType {
return p.keyType
}
func (p *tMap) ValueType() TType {
return p.valueType
}
func (p *tMap) Len() int {
if p.l.Len() != 0 {
return p.l.Len()
}
switch p.KeyType() {
case STOP, VOID:
return 0
case BOOL:
return len(p.b)
case BYTE:
return len(p.i08)
case I16:
return len(p.i16)
case I32:
return len(p.i32)
case I64:
return len(p.i64)
case DOUBLE:
return len(p.f64)
case STRING, UTF8, UTF16:
return len(p.s)
default:
return p.size
}
return p.size
}
func (p *tMap) Get(key interface{}) (interface{}, bool) {
if p.KeyType().IsEmptyType() {
return nil, false
}
if key == nil {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
e := elem.Value.(TMapElem)
k := e.Key()
if k == nil {
return e.Value(), true
}
}
return nil, false
}
useKey, ok := p.KeyType().CoerceData(key)
if !ok {
return nil, false
}
switch p.KeyType() {
case STOP, VOID:
// if here, then we don't have a key type yet and key is not nil
// so this is pretty much an empty map
return nil, false
case BOOL:
m := p.b
if m == nil {
return nil, false
}
if v, ok := m[useKey.(bool)]; ok {
return v, true
}
return nil, true
case BYTE:
m := p.i08
if v, ok := m[useKey.(byte)]; ok {
return v, true
}
return nil, false
case DOUBLE:
m := p.f64
if m == nil {
return nil, false
}
if v, ok := m[useKey.(float64)]; ok {
return v, true
}
return nil, false
case I16:
m := p.i16
if m == nil {
return nil, false
}
if v, ok := m[useKey.(int16)]; ok {
return v, true
}
return nil, false
case I32:
m := p.i32
if m == nil {
return nil, false
}
if v, ok := m[useKey.(int32)]; ok {
return v, true
}
return nil, false
case I64:
m := p.i64
if m == nil {
return nil, false
}
if v, ok := m[useKey.(int64)]; ok {
return v, true
}
return nil, false
case STRING, UTF8, UTF16:
// TODO(pomack) properly handle ENUM
m := p.s
if m == nil {
return nil, false
}
if v, ok := m[useKey.(string)]; ok {
return v, true
}
return nil, false
case STRUCT:
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
e := elem.Value.(TMapElem)
k := e.Key()
if k == nil {
continue
}
structkey, ok := k.(TStruct)
if ok {
if structkey.Equals(useKey.(TStruct)) {
return e.Value(), true
}
continue
}
if reflect.DeepEqual(useKey, k) {
return e.Value(), true
}
}
return nil, false
case MAP:
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
e := elem.Value.(TMapElem)
k := e.Key()
if k == nil {
continue
}
mapkey, ok := k.(TMap)
if ok {
if mapkey.Equals(useKey.(TMap)) {
return e.Value(), true
}
continue
}
if reflect.DeepEqual(useKey, k) {
return e.Value(), true
}
}
return nil, false
case SET:
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
e := elem.Value.(TMapElem)
k := e.Key()
if k == nil {
continue
}
setkey, ok := k.(TSet)
if ok {
if setkey.Equals(useKey.(TSet)) {
return e.Value(), true
}
continue
}
if reflect.DeepEqual(useKey, k) {
return e.Value(), true
}
}
return nil, false
case LIST:
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
e := elem.Value.(TMapElem)
k := e.Key()
if k == nil {
continue
}
listkey, ok := k.(TList)
if ok {
if listkey.Equals(useKey.(TList)) {
return e.Value(), true
}
continue
}
if reflect.DeepEqual(useKey, k) {
return e.Value(), true
}
}
return nil, false
default:
panic("Invalid Thrift element type")
}
return nil, false
}
func (p *tMap) Set(key, value interface{}) {
if p.KeyType() == STOP || p.KeyType() == VOID {
p.keyType = TypeFromValue(key)
}
coercedKey, ok := p.KeyType().CoerceData(key)
if !ok {
return
}
if p.ValueType() == STOP || p.ValueType() == VOID {
p.valueType = TypeFromValue(value)
}
coercedValue, ok := p.ValueType().CoerceData(value)
if !ok {
return
}
newElem := NewTMapElem(coercedKey, coercedValue)
if !p.KeyType().IsBaseType() {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
k := elem.Value.(TMapElem).Key()
if cmp, ok := p.KeyType().Compare(coercedKey, k); ok && cmp >= 0 {
if cmp == 0 {
p.l.InsertAfter(newElem, elem)
p.l.Remove(elem)
return
}
p.l.InsertBefore(newElem, elem)
return
}
}
p.l.PushBack(newElem)
return
}
if key == nil {
return
}
switch p.KeyType() {
case STOP, VOID:
// if here, then we don't have a key type yet and key is not nil
// so this is pretty much an empty map
return
case BOOL:
if p.b == nil {
p.b = make(map[bool]interface{})
}
b := coercedKey.(bool)
p.b[b] = value
case BYTE:
if p.i08 == nil {
p.i08 = make(map[byte]interface{})
}
b := coercedKey.(byte)
p.i08[b] = value
case DOUBLE:
if p.f64 == nil {
p.f64 = make(map[float64]interface{})
}
b := coercedKey.(float64)
p.f64[b] = value
case I16:
if p.i16 == nil {
p.i16 = make(map[int16]interface{})
}
b := coercedKey.(int16)
p.i16[b] = value
case I32:
if p.i32 == nil {
p.i32 = make(map[int32]interface{})
}
b := coercedKey.(int32)
p.i32[b] = value
case I64:
if p.i64 == nil {
p.i64 = make(map[int64]interface{})
}
b := coercedKey.(int64)
p.i64[b] = value
case STRING, UTF8, UTF16:
if p.s == nil {
p.s = make(map[string]interface{})
}
b := coercedKey.(string)
p.s[b] = value
case STRUCT, MAP, SET, LIST:
panic("Should never be here")
default:
panic("Should never be here")
}
}
func (p *tMap) Contains(key interface{}) bool {
coercedKey, ok := p.KeyType().CoerceData(key)
if !ok {
return false
}
if coercedKey == nil {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
k := elem.Value.(TMapElem).Key()
if k == nil {
return true
}
}
return false
}
if !ok {
return false
}
switch p.KeyType() {
case STOP:
// if here, then we don't have a key type yet and key is not nil
// so this is pretty much an empty map
return false
case VOID:
// if here, then we don't have a key type yet and key is not nil
// so this is pretty much an empty map
return false
case BOOL:
m := p.b
if m == nil {
return false
}
_, ok := m[coercedKey.(bool)]
return ok
case BYTE:
m := p.i08
_, ok := m[coercedKey.(byte)]
return ok
case DOUBLE:
m := p.f64
if m == nil {
return false
}
_, ok := m[coercedKey.(float64)]
return ok
case I16:
m := p.i16
if m == nil {
return false
}
_, ok := m[coercedKey.(int16)]
return ok
case I32:
m := p.i32
if m == nil {
return false
}
_, ok := m[coercedKey.(int32)]
return ok
case I64:
m := p.i64
if m == nil {
return false
}
_, ok := m[coercedKey.(int64)]
return ok
case STRING, UTF8, UTF16:
// TODO(pomack) properly handle ENUM
m := p.s
if m == nil {
return false
}
_, ok := m[coercedKey.(string)]
return ok
case STRUCT:
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
e := elem.Value.(TMapElem)
k := e.Key()
if k == nil {
continue
}
structkey, ok := k.(TStruct)
if ok {
if structkey.Equals(coercedKey.(TStruct)) {
return true
}
continue
}
if reflect.DeepEqual(coercedKey, k) {
return true
}
}
return false
case MAP:
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
e := elem.Value.(TMapElem)
k := e.Key()
if k == nil {
continue
}
mapkey, ok := k.(TMap)
if ok {
if mapkey.Equals(coercedKey.(TMap)) {
return true
}
continue
}
}
return false
case SET:
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
e := elem.Value.(TMapElem)
k := e.Key()
if k == nil {
continue
}
setkey, ok := k.(TSet)
if ok {
if setkey.Equals(coercedKey.(TSet)) {
return true
}
continue
}
}
return false
case LIST:
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
e := elem.Value.(TMapElem)
k := e.Key()
if k == nil {
continue
}
listkey, ok := k.(TList)
if ok {
if listkey.Equals(coercedKey.(TList)) {
return true
}
continue
}
}
return false
default:
panic("Invalid Thrift element type")
}
return false
}
// Iterate over all elements; driver for range
func (p *tMap) iterate(c chan<- TMapElem) {
switch p.KeyType() {
case STOP, VOID:
close(c)
case BOOL:
for k, v := range p.b {
c <- NewTMapElem(k, v)
}
close(c)
case BYTE:
for k, v := range p.i08 {
c <- NewTMapElem(k, v)
}
close(c)
case I16:
for k, v := range p.i16 {
c <- NewTMapElem(k, v)
}
close(c)
case I32:
for k, v := range p.i32 {
c <- NewTMapElem(k, v)
}
close(c)
case I64:
for k, v := range p.i64 {
c <- NewTMapElem(k, v)
}
close(c)
case DOUBLE:
for k, v := range p.f64 {
c <- NewTMapElem(k, v)
}
close(c)
case STRING, UTF8, UTF16:
for k, v := range p.s {
c <- NewTMapElem(k, v)
}
close(c)
case STRUCT:
for v := p.l.Front(); v != nil; v = v.Next() {
c <- v.Value.(TMapElem)
}
close(c)
case LIST:
for v := p.l.Front(); v != nil; v = v.Next() {
c <- v.Value.(TMapElem)
}
close(c)
case SET:
for v := p.l.Front(); v != nil; v = v.Next() {
c <- v.Value.(TMapElem)
}
close(c)
default:
panic("Invalid Thrift type")
}
}
// Channel iterator for range.
func (p *tMap) Iter() <-chan TMapElem {
c := make(chan TMapElem)
go p.iterate(c)
return c
}
// Iterate over all keys; driver for range
func (p *tMap) iterateKeys(c chan<- interface{}) {
switch p.KeyType() {
case STOP, VOID:
close(c)
case BOOL:
for k, _ := range p.b {
c <- k
}
close(c)
case BYTE:
for k, _ := range p.i08 {
c <- k
}
close(c)
case I16:
for k, _ := range p.i16 {
c <- k
}
close(c)
case I32:
for k, _ := range p.i32 {
c <- k
}
close(c)
case I64:
for k, _ := range p.i64 {
c <- k
}
close(c)
case DOUBLE:
for k, _ := range p.f64 {
c <- k
}
close(c)
case STRING, UTF8, UTF16:
for k, _ := range p.s {
c <- k
}
close(c)
case STRUCT:
for v := p.l.Front(); v != nil; v = v.Next() {
c <- v.Value.(TMapElem).Key()
}
close(c)
case LIST:
for v := p.l.Front(); v != nil; v = v.Next() {
c <- v.Value.(TMapElem).Key()
}
close(c)
case SET:
for v := p.l.Front(); v != nil; v = v.Next() {
c <- v.Value.(TMapElem).Key()
}
close(c)
default:
panic("Invalid Thrift type")
}
}
func (p *tMap) KeyIter() <-chan interface{} {
c := make(chan interface{})
go p.iterateKeys(c)
return c
}
// Iterate over all values; driver for range
func (p *tMap) iterateValues(c chan<- interface{}) {
switch p.KeyType() {
case STOP, VOID:
close(c)
case BOOL:
for _, v := range p.b {
c <- v
}
close(c)
case BYTE:
for _, v := range p.i08 {
c <- v
}
close(c)
case I16:
for _, v := range p.i16 {
c <- v
}
close(c)
case I32:
for _, v := range p.i32 {
c <- v
}
close(c)
case I64:
for _, v := range p.i64 {
c <- v
}
close(c)
case DOUBLE:
for _, v := range p.f64 {
c <- v
}
close(c)
case STRING, UTF8, UTF16:
for _, v := range p.s {
c <- v
}
close(c)
case STRUCT:
for v := p.l.Front(); v != nil; v = v.Next() {
c <- v.Value.(TMapElem).Value()
}
close(c)
case LIST:
for v := p.l.Front(); v != nil; v = v.Next() {
c <- v.Value.(TMapElem).Value()
}
close(c)
case SET:
for v := p.l.Front(); v != nil; v = v.Next() {
c <- v.Value.(TMapElem).Value()
}
close(c)
default:
panic("Invalid Thrift type")
}
}
func (p *tMap) ValueIter() <-chan interface{} {
c := make(chan interface{})
go p.iterateValues(c)
return c
}
func (p *tMap) Less(other interface{}) bool {
cmp, ok := p.CompareTo(other)
return ok && cmp > 0
}
func (p *tMap) Equals(other interface{}) bool {
c, cok := p.CompareTo(other)
return cok && c == 0
}
func (p *tMap) CompareTo(other interface{}) (int, bool) {
return TType(MAP).Compare(p, other)
}
func (p *tMap) Keys() []interface{} {
size := p.Len()
values := make([]interface{}, size, size)
i := 0
for k := range p.KeyIter() {
values[i] = k
i++
}
return values
}
func (p *tMap) Values() []interface{} {
size := p.Len()
values := make([]interface{}, size, size)
i := 0
for v := range p.ValueIter() {
values[i] = v
i++
}
return values
}