func (c *columnString) FilterString(offset uint32, index bitmap.Bitmap, predicate func(v string) bool) {
	index.And(c.fill[offset>>6 : int(offset>>6)+len(index)])
	index.Filter(func(idx uint32) (match bool) {
		idx = offset + idx
		return idx < uint32(len(c.data)) && predicate(c.data[idx])
	})
}
FilterString filters down the values based on the specified predicate. The column for
this filter must be a string.
package column
import (
	"encoding/binary"
	"hash/crc32"
	"math"
	"reflect"
	"sync"
	"unsafe"
	"github.com/kelindar/bitmap"
	"github.com/kelindar/column/commit"
)
var _ Textual = new(columnEnum)
type columnEnum struct {
	lock  sync.RWMutex
	fill  bitmap.Bitmap      
	locs  []uint32           
	data  []byte             
	cache map[string]uint32  
}
func makeEnum() Column {
	return &columnEnum{
		fill:  make(bitmap.Bitmap, 0, 4),
		locs:  make([]uint32, 0, 64),
		data:  make([]byte, 0, 16*32),
		cache: make(map[string]uint32, 16),
	}
}
func (c *columnEnum) Grow(idx uint32) {
	if idx < uint32(len(c.locs)) {
		return
	}
	if idx < uint32(cap(c.locs)) {
		c.fill.Grow(idx)
		c.locs = c.locs[:idx+1]
		return
	}
	c.fill.Grow(idx)
	clone := make([]uint32, idx+1, capacityFor(idx+1))
	copy(clone, c.locs)
	c.locs = clone
}
func (c *columnEnum) Apply(r *commit.Reader) {
	for r.Next() {
		switch r.Type {
		case commit.Put:
			value := r.String()
			c.lock.RLock()
			offset, cached := c.cache[value]
			c.lock.RUnlock()
			if !cached {
				c.lock.Lock()
				offset = c.findOrAdd(value)
				c.cache[value] = offset
				c.lock.Unlock()
			}
			c.fill[r.Offset>>6] |= 1 << (r.Offset & 0x3f)
			c.locs[r.Offset] = offset
		case commit.Delete:
			c.fill.Remove(r.Index())
		}
	}
}
func (c *columnEnum) findOrAdd(v string) uint32 {
	value := toBytes(v)
	target := crc32.ChecksumIEEE(value)
	for i := 0; i < len(c.data); {
		hash := binary.BigEndian.Uint32(c.data[i : i+4])
		size := int(c.data[i+4])
		if hash == target {
			return uint32(i + 4)
		}
		i += 5 + size
	}
	var head [5]byte
	binary.BigEndian.PutUint32(head[0:4], target)
	head[4] = byte(len(value))  
	addedAt := len(c.data)
	c.data = append(c.data, head[:]...)
	c.data = append(c.data, value...)
	return uint32(addedAt + 4)
}
func (c *columnEnum) readAt(at uint32) string {
	size := uint32(c.data[at])
	data := c.data[at+1 : at+1+size]
	return toString(&data)
}
func (c *columnEnum) Value(idx uint32) (v interface{}, ok bool) {
	return c.LoadString(idx)
}
func (c *columnEnum) LoadString(idx uint32) (v string, ok bool) {
	if idx < uint32(len(c.locs)) && c.fill.Contains(idx) {
		v, ok = c.readAt(c.locs[idx]), true
	}
	return
}
func (c *columnEnum) FilterString(offset uint32, index bitmap.Bitmap, predicate func(v string) bool) {
	cache := struct {
		index uint32  
		value bool    
	}{}
	cache.index = math.MaxUint32
	index.And(c.fill[offset>>6 : int(offset>>6)+len(index)])
	index.Filter(func(idx uint32) bool {
		idx = offset + idx
		if at := c.locs[idx]; at != cache.index {
			cache.index = at
			cache.value = predicate(c.readAt(at))
			return cache.value
		}
		return cache.value
	})
}
func (c *columnEnum) Contains(idx uint32) bool {
	return c.fill.Contains(idx)
}
func (c *columnEnum) Index() *bitmap.Bitmap {
	return &c.fill
}
var _ Textual = new(columnString)
type columnString struct {
	fill bitmap.Bitmap  
	data []string       
}
func makeStrings() Column {
	return &columnString{
		fill: make(bitmap.Bitmap, 0, 4),
		data: make([]string, 0, 64),
	}
}
func (c *columnString) Grow(idx uint32) {
	if idx < uint32(len(c.data)) {
		return
	}
	if idx < uint32(cap(c.data)) {
		c.fill.Grow(idx)
		c.data = c.data[:idx+1]
		return
	}
	c.fill.Grow(idx)
	clone := make([]string, idx+1, capacityFor(idx+1))
	copy(clone, c.data)
	c.data = clone
}
func (c *columnString) Apply(r *commit.Reader) {
	for r.Next() {
		switch r.Type {
		case commit.Put:
			c.fill[r.Offset>>6] |= 1 << (r.Offset & 0x3f)
			c.data[r.Offset] = string(r.Bytes())
		case commit.Delete:
			c.fill.Remove(r.Index())
		}
	}
}
func (c *columnString) Value(idx uint32) (v interface{}, ok bool) {
	if idx < uint32(len(c.data)) && c.fill.Contains(idx) {
		v, ok = c.data[idx], true
	}
	return
}
func (c *columnString) Contains(idx uint32) bool {
	return c.fill.Contains(idx)
}
func (c *columnString) Index() *bitmap.Bitmap {
	return &c.fill
}
func (c *columnString) LoadString(idx uint32) (string, bool) {
	v, has := c.Value(idx)
	s, ok := v.(string)
	return s, has && ok
}