github.com/tobgu/qframe@v0.4.0/internal/icolumn/column.go (about)

     1  package icolumn
     2  
     3  import (
     4  	"github.com/tobgu/qframe/internal/column"
     5  	"github.com/tobgu/qframe/internal/hash"
     6  	"github.com/tobgu/qframe/internal/index"
     7  	"github.com/tobgu/qframe/qerrors"
     8  	"github.com/tobgu/qframe/types"
     9  	"reflect"
    10  	"strconv"
    11  	"unsafe"
    12  )
    13  
    14  func (c Column) DataType() types.DataType {
    15  	return types.Int
    16  }
    17  
    18  func (c Column) StringAt(i uint32, _ string) string {
    19  	return strconv.FormatInt(int64(c.data[i]), 10)
    20  }
    21  
    22  func (c Column) AppendByteStringAt(buf []byte, i uint32) []byte {
    23  	return strconv.AppendInt(buf, int64(c.data[i]), 10)
    24  }
    25  
    26  func (c Column) ByteSize() int {
    27  	// Slice header + data
    28  	return 2*8 + 8*cap(c.data)
    29  }
    30  
    31  func (c Column) Equals(index index.Int, other column.Column, otherIndex index.Int) bool {
    32  	otherI, ok := other.(Column)
    33  	if !ok {
    34  		return false
    35  	}
    36  
    37  	for ix, x := range index {
    38  		if c.data[x] != otherI.data[otherIndex[ix]] {
    39  			return false
    40  		}
    41  	}
    42  
    43  	return true
    44  }
    45  
    46  func (c Column) FloatSlice() []float64 {
    47  	result := make([]float64, len(c.data))
    48  	for i, v := range c.data {
    49  		result[i] = float64(v)
    50  	}
    51  
    52  	return result
    53  }
    54  
    55  func (c Comparable) Compare(i, j uint32) column.CompareResult {
    56  	x, y := c.data[i], c.data[j]
    57  	if x < y {
    58  		return c.ltValue
    59  	}
    60  
    61  	if x > y {
    62  		return c.gtValue
    63  	}
    64  
    65  	return column.Equal
    66  }
    67  
    68  func (c Comparable) Hash(i uint32, seed uint64) uint64 {
    69  	x := &c.data[i]
    70  	b := (*[8]byte)(unsafe.Pointer(x))[:]
    71  	return hash.HashBytes(b, seed)
    72  }
    73  
    74  func intComp(comparatee interface{}) (int, bool) {
    75  	comp, ok := comparatee.(int)
    76  	if !ok {
    77  		// Accept floats by truncating them
    78  		compFloat, ok := comparatee.(float64)
    79  		if !ok {
    80  			return 0, false
    81  		}
    82  		comp = int(compFloat)
    83  	}
    84  
    85  	return comp, true
    86  }
    87  
    88  type intSet map[int]struct{}
    89  
    90  func interfaceSliceToIntSlice(ss []interface{}) ([]int, bool) {
    91  	result := make([]int, len(ss))
    92  	for i, s := range ss {
    93  		switch t := s.(type) {
    94  		case int:
    95  			result[i] = t
    96  		case float64:
    97  			result[i] = int(t)
    98  		default:
    99  			return nil, false
   100  		}
   101  	}
   102  	return result, true
   103  }
   104  
   105  func newIntSet(input interface{}) (intSet, bool) {
   106  	var result intSet
   107  	var ok bool
   108  	switch t := input.(type) {
   109  	case []int:
   110  		result, ok = make(intSet, len(t)), true
   111  		for _, v := range t {
   112  			result[v] = struct{}{}
   113  		}
   114  	case []float64:
   115  		result, ok = make(intSet, len(t)), true
   116  		for _, v := range t {
   117  			result[int(v)] = struct{}{}
   118  		}
   119  	case []interface{}:
   120  		if intSlice, innerOk := interfaceSliceToIntSlice(t); innerOk {
   121  			result, ok = newIntSet(intSlice)
   122  		}
   123  	}
   124  
   125  	return result, ok
   126  }
   127  
   128  func (is intSet) Contains(x int) bool {
   129  	_, ok := is[x]
   130  	return ok
   131  }
   132  
   133  func (c Column) filterBuiltIn(index index.Int, comparator string, comparatee interface{}, bIndex index.Bool) error {
   134  	if intC, ok := intComp(comparatee); ok {
   135  		filterFn, ok := filterFuncs[comparator]
   136  		if !ok {
   137  			return qerrors.New("filter int", "unknown filter operator %v", comparator)
   138  		}
   139  		filterFn(index, c.data, intC, bIndex)
   140  	} else if set, ok := newIntSet(comparatee); ok {
   141  		filterFn, ok := multiInputFilterFuncs[comparator]
   142  		if !ok {
   143  			return qerrors.New("filter int", "unknown filter operator %v", comparator)
   144  		}
   145  		filterFn(index, c.data, set, bIndex)
   146  	} else if columnC, ok := comparatee.(Column); ok {
   147  		filterFn, ok := filterFuncs2[comparator]
   148  		if !ok {
   149  			return qerrors.New("filter int", "unknown filter operator %v", comparator)
   150  		}
   151  		filterFn(index, c.data, columnC.data, bIndex)
   152  	} else if comparatee == nil {
   153  		compFunc, ok := filterFuncs0[comparator]
   154  		if !ok {
   155  			return qerrors.New("filter int", "invalid comparison operator to zero argument filter, %v", comparator)
   156  		}
   157  		compFunc(index, c.data, bIndex)
   158  	} else {
   159  		return qerrors.New("filter int", "invalid comparison value type %v", reflect.TypeOf(comparatee))
   160  	}
   161  
   162  	return nil
   163  }
   164  
   165  func (c Column) filterCustom1(index index.Int, fn func(int) bool, bIndex index.Bool) {
   166  	for i, x := range bIndex {
   167  		if !x {
   168  			bIndex[i] = fn(c.data[index[i]])
   169  		}
   170  	}
   171  }
   172  
   173  func (c Column) filterCustom2(index index.Int, fn func(int, int) bool, comparatee interface{}, bIndex index.Bool) error {
   174  	otherC, ok := comparatee.(Column)
   175  	if !ok {
   176  		return qerrors.New("filter int", "expected comparatee to be int column, was %v", reflect.TypeOf(comparatee))
   177  	}
   178  
   179  	for i, x := range bIndex {
   180  		if !x {
   181  			bIndex[i] = fn(c.data[index[i]], otherC.data[index[i]])
   182  		}
   183  	}
   184  
   185  	return nil
   186  }
   187  
   188  func (c Column) Filter(index index.Int, comparator interface{}, comparatee interface{}, bIndex index.Bool) error {
   189  	var err error
   190  	switch t := comparator.(type) {
   191  	case string:
   192  		err = c.filterBuiltIn(index, t, comparatee, bIndex)
   193  	case func(int) bool:
   194  		c.filterCustom1(index, t, bIndex)
   195  	case func(int, int) bool:
   196  		err = c.filterCustom2(index, t, comparatee, bIndex)
   197  	default:
   198  		err = qerrors.New("filter int", "invalid filter type %v", reflect.TypeOf(comparator))
   199  	}
   200  	return err
   201  }
   202  
   203  func (c Column) FunctionType() types.FunctionType {
   204  	return types.FunctionTypeInt
   205  }
   206  
   207  func (c Column) Append(cols ...column.Column) (column.Column, error) {
   208  	// TODO Improve, currently copies all data over to a new column, this may not be the best solution...
   209  	newLen := c.Len()
   210  	intCols := append(make([]Column, 0, len(cols)+1), c)
   211  	for _, col := range cols {
   212  		intCol, ok := col.(Column)
   213  		if !ok {
   214  			return nil, qerrors.New("append int", "can only append integer columns to integer column")
   215  		}
   216  		newLen += intCol.Len()
   217  		intCols = append(intCols, intCol)
   218  	}
   219  
   220  	newData := make([]int, newLen)
   221  	offset := 0
   222  	for _, col := range intCols {
   223  		offset += copy(newData[offset:], col.data)
   224  	}
   225  
   226  	return New(newData), nil
   227  }