2015-01-01 19:49:30 +00:00
|
|
|
package fzf
|
|
|
|
|
|
|
|
import "sync"
|
|
|
|
|
2017-07-15 03:28:29 +00:00
|
|
|
// Chunk is a list of Items whose size has the upper limit of chunkSize
|
2017-08-14 16:10:41 +00:00
|
|
|
type Chunk struct {
|
|
|
|
items [chunkSize]Item
|
|
|
|
count int
|
|
|
|
}
|
2015-01-01 19:49:30 +00:00
|
|
|
|
2017-08-16 03:26:06 +00:00
|
|
|
// ItemBuilder is a closure type that builds Item object from byte array
|
|
|
|
type ItemBuilder func(*Item, []byte) bool
|
2015-01-01 19:49:30 +00:00
|
|
|
|
2015-01-11 18:01:24 +00:00
|
|
|
// ChunkList is a list of Chunks
|
2015-01-01 19:49:30 +00:00
|
|
|
type ChunkList struct {
|
|
|
|
chunks []*Chunk
|
|
|
|
mutex sync.Mutex
|
2015-01-12 03:56:17 +00:00
|
|
|
trans ItemBuilder
|
2015-01-01 19:49:30 +00:00
|
|
|
}
|
|
|
|
|
2015-01-11 18:01:24 +00:00
|
|
|
// NewChunkList returns a new ChunkList
|
2015-01-12 03:56:17 +00:00
|
|
|
func NewChunkList(trans ItemBuilder) *ChunkList {
|
2015-01-01 19:49:30 +00:00
|
|
|
return &ChunkList{
|
|
|
|
chunks: []*Chunk{},
|
|
|
|
mutex: sync.Mutex{},
|
|
|
|
trans: trans}
|
|
|
|
}
|
|
|
|
|
2017-08-16 03:26:06 +00:00
|
|
|
func (c *Chunk) push(trans ItemBuilder, data []byte) bool {
|
|
|
|
if trans(&c.items[c.count], data) {
|
2017-08-14 16:10:41 +00:00
|
|
|
c.count++
|
|
|
|
return true
|
2015-07-21 18:21:20 +00:00
|
|
|
}
|
2017-08-14 16:10:41 +00:00
|
|
|
return false
|
2015-01-01 19:49:30 +00:00
|
|
|
}
|
|
|
|
|
2015-01-11 18:01:24 +00:00
|
|
|
// IsFull returns true if the Chunk is full
|
2015-01-01 19:49:30 +00:00
|
|
|
func (c *Chunk) IsFull() bool {
|
2017-08-14 16:10:41 +00:00
|
|
|
return c.count == chunkSize
|
2015-01-01 19:49:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (cl *ChunkList) lastChunk() *Chunk {
|
|
|
|
return cl.chunks[len(cl.chunks)-1]
|
|
|
|
}
|
|
|
|
|
2015-01-11 18:01:24 +00:00
|
|
|
// CountItems returns the total number of Items
|
2015-01-01 19:49:30 +00:00
|
|
|
func CountItems(cs []*Chunk) int {
|
|
|
|
if len(cs) == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
2017-08-14 16:10:41 +00:00
|
|
|
return chunkSize*(len(cs)-1) + cs[len(cs)-1].count
|
2015-01-01 19:49:30 +00:00
|
|
|
}
|
|
|
|
|
2015-01-11 18:01:24 +00:00
|
|
|
// Push adds the item to the list
|
2015-08-02 05:25:57 +00:00
|
|
|
func (cl *ChunkList) Push(data []byte) bool {
|
2015-01-01 19:49:30 +00:00
|
|
|
cl.mutex.Lock()
|
|
|
|
|
|
|
|
if len(cl.chunks) == 0 || cl.lastChunk().IsFull() {
|
2017-08-14 16:10:41 +00:00
|
|
|
cl.chunks = append(cl.chunks, &Chunk{})
|
2015-01-01 19:49:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-16 03:26:06 +00:00
|
|
|
ret := cl.lastChunk().push(cl.trans, data)
|
2017-07-31 18:39:57 +00:00
|
|
|
cl.mutex.Unlock()
|
2017-08-16 03:26:06 +00:00
|
|
|
return ret
|
2015-01-01 19:49:30 +00:00
|
|
|
}
|
|
|
|
|
2019-11-10 02:36:22 +00:00
|
|
|
// Clear clears the data
|
|
|
|
func (cl *ChunkList) Clear() {
|
|
|
|
cl.mutex.Lock()
|
|
|
|
cl.chunks = nil
|
|
|
|
cl.mutex.Unlock()
|
|
|
|
}
|
|
|
|
|
2015-01-11 18:01:24 +00:00
|
|
|
// Snapshot returns immutable snapshot of the ChunkList
|
2015-01-03 20:01:13 +00:00
|
|
|
func (cl *ChunkList) Snapshot() ([]*Chunk, int) {
|
2015-01-01 19:49:30 +00:00
|
|
|
cl.mutex.Lock()
|
|
|
|
|
|
|
|
ret := make([]*Chunk, len(cl.chunks))
|
|
|
|
copy(ret, cl.chunks)
|
2015-01-03 20:01:13 +00:00
|
|
|
|
|
|
|
// Duplicate the last chunk
|
|
|
|
if cnt := len(ret); cnt > 0 {
|
2017-07-15 07:58:21 +00:00
|
|
|
newChunk := *ret[cnt-1]
|
|
|
|
ret[cnt-1] = &newChunk
|
2015-01-03 20:01:13 +00:00
|
|
|
}
|
2017-07-31 18:39:57 +00:00
|
|
|
|
|
|
|
cl.mutex.Unlock()
|
2017-08-16 03:26:06 +00:00
|
|
|
return ret, CountItems(ret)
|
2015-01-03 20:01:13 +00:00
|
|
|
}
|