blob: f8681098bd863600d4912370bb52accf65926a46 [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"
)
/**
* Helper class that encapsulates set metadata.
*
*/
type TSet interface {
TContainer
ElemType() TType
Add(data interface{})
Remove(data interface{})
Less(other interface{}) bool
Front() *list.Element
Back() *list.Element
Values() []interface{}
}
type tSet struct {
elemType TType
size int
l *list.List
}
func NewTSet(t TType, s int) TSet {
return &tSet{elemType: t, size: s, l: list.New()}
}
func NewTSetDefault() TSet {
return NewTSet(STOP, 0)
}
func (p *tSet) ElemType() TType {
return p.elemType
}
func (p *tSet) Front() *list.Element {
return p.l.Front()
}
func (p *tSet) Back() *list.Element {
return p.l.Back()
}
func (p *tSet) Len() int {
if p.l.Len() != 0 {
return p.l.Len()
}
return p.size
}
func (p *tSet) Contains(data interface{}) bool {
return p.find(data) != nil
}
func (p *tSet) Add(other interface{}) {
if data, ok := p.elemType.CoerceData(other); ok {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
if cmp, ok := p.elemType.Compare(data, elem.Value); ok && cmp >= 0 {
if cmp > 0 {
p.l.InsertBefore(data, elem)
}
return
}
}
}
}
func (p *tSet) Remove(data interface{}) {
elem := p.find(data)
if elem != nil {
p.l.Remove(elem)
}
}
func (p *tSet) Less(other interface{}) bool {
cmp, ok := p.CompareTo(other)
return ok && cmp > 0
}
func (p *tSet) Equals(other interface{}) bool {
c, cok := p.CompareTo(other)
return cok && c == 0
}
func (p *tSet) CompareTo(other interface{}) (int, bool) {
return TType(SET).Compare(p, other)
}
func (p *tSet) find(data interface{}) *list.Element {
if data == nil {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
if elem.Value == nil {
return elem
}
}
return nil
}
data, ok := p.elemType.CoerceData(data)
if data == nil || !ok {
return nil
}
if p.elemType.IsBaseType() || p.elemType.IsEnum() {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
if data == elem.Value {
return elem
}
}
return nil
}
if cmp, ok := data.(EqualsOtherInterface); ok {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
if cmp.Equals(elem.Value) {
return elem
}
}
return nil
}
switch p.elemType {
case MAP:
if cmp, ok := data.(EqualsMap); ok {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
v := elem.Value
if v == nil {
continue
}
if cmp.Equals(v.(TMap)) {
return elem
}
}
return nil
}
case SET:
if cmp, ok := data.(EqualsSet); ok {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
v := elem.Value
if v == nil {
continue
}
if cmp.Equals(v.(TSet)) {
return elem
}
}
return nil
}
case LIST:
if cmp, ok := data.(EqualsList); ok {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
v := elem.Value
if v == nil {
continue
}
if cmp.Equals(v.(TList)) {
return elem
}
}
return nil
}
case STRUCT:
if cmp, ok := data.(EqualsStruct); ok {
for elem := p.l.Front(); elem != nil; elem = elem.Next() {
v := elem.Value
if v == nil {
continue
}
if cmp.Equals(v.(TStruct)) {
return elem
}
}
return nil
}
}
return nil
}
func (p *tSet) Values() []interface{} {
size := p.l.Len()
values := make([]interface{}, size, size)
i := 0
for v := p.l.Front(); v != nil; v = v.Next() {
values[i] = v.Value
i++
}
return values
}