Initial tiling code.
[lightning.git] / taglib.go
1 package main
2
3 import (
4         "bufio"
5         "bytes"
6         "fmt"
7         "io"
8 )
9
10 const tagmapKeySize = 24
11
12 type tagmapKey [tagmapKeySize]byte
13
14 type tagID int32
15
16 type tagInfo struct {
17         id     tagID // 0-based position in input tagset
18         tagseq []byte
19 }
20
21 type tagLibrary struct {
22         tagmap map[tagmapKey]tagInfo
23         keylen int
24 }
25
26 func (taglib *tagLibrary) Load(rdr io.Reader) error {
27         var seqs [][]byte
28         scanner := bufio.NewScanner(rdr)
29         for scanner.Scan() {
30                 data := scanner.Bytes()
31                 if len(data) > 0 && data[0] == '>' {
32                 } else {
33                         seqs = append(seqs, append([]byte(nil), data...))
34                 }
35         }
36         if err := scanner.Err(); err != nil {
37                 return err
38         }
39         return taglib.setTags(seqs)
40 }
41
42 type tagMatch struct {
43         id  tagID
44         pos int
45 }
46
47 func (taglib *tagLibrary) FindAll(buf []byte, fn func(id tagID, pos int)) {
48         var key tagmapKey
49         for i := 0; i <= len(buf)-taglib.keylen; i++ {
50                 copy(key[:taglib.keylen], buf[i:])
51                 if taginfo, ok := taglib.tagmap[key]; !ok {
52                         continue
53                 } else if len(taginfo.tagseq) > taglib.keylen && (len(buf) < i+len(taginfo.tagseq) || !bytes.Equal(taginfo.tagseq, buf[i:i+len(taginfo.tagseq)])) {
54                         // key portion matches, but not the entire tag
55                         continue
56                 } else {
57                         fn(taginfo.id, i)
58                 }
59         }
60 }
61
62 func (taglib *tagLibrary) Len() int {
63         return len(taglib.tagmap)
64 }
65
66 func (taglib *tagLibrary) setTags(tags [][]byte) error {
67         taglib.keylen = tagmapKeySize
68         for _, t := range tags {
69                 if l := len(t); taglib.keylen > l {
70                         taglib.keylen = l
71                 }
72         }
73         taglib.tagmap = map[tagmapKey]tagInfo{}
74         for i, t := range tags {
75                 t = bytes.ToLower(t)
76                 var key tagmapKey
77                 copy(key[:], t[:taglib.keylen])
78                 if _, ok := taglib.tagmap[key]; ok {
79                         return fmt.Errorf("first %d bytes of tag %d (%s) are not unique", taglib.keylen, i, key)
80                 }
81                 taglib.tagmap[key] = tagInfo{tagID(i), t}
82         }
83         return nil
84 }