|
| 1 | +// contributed by Branimir Maksimovic |
| 2 | + |
| 3 | +package main |
| 4 | +import "core:fmt" |
| 5 | +import "core:os" |
| 6 | +import "core:strings" |
| 7 | +import "core:bufio" |
| 8 | +import "core:io" |
| 9 | +import "core:thread" |
| 10 | +import "core:slice" |
| 11 | + |
| 12 | +FACTOR :: 16 |
| 13 | +main :: proc() { |
| 14 | + initTables() |
| 15 | + buf,err := read_lines_with_buffering() |
| 16 | + defer delete(buf) |
| 17 | + if err != io.Error.No_Progress { |
| 18 | + fmt.println("error:",err) |
| 19 | + return |
| 20 | + } |
| 21 | + Value :: union{u8,string} |
| 22 | + data:[]Value = { 1, 2 , "GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT" } |
| 23 | + for i in data { |
| 24 | + switch j in i { |
| 25 | + case u8:work(&buf,j) |
| 26 | + case string:work(&buf,j) |
| 27 | + } |
| 28 | + } |
| 29 | +} |
| 30 | +frequencies :: proc (buf:^string, count: u8) { |
| 31 | + hash := calculate(buf,cast(u32)count) |
| 32 | + defer delete_table(hash) |
| 33 | + list := make([dynamic]Value,0) |
| 34 | + defer { |
| 35 | + for i in list{ |
| 36 | + delete(i.key) |
| 37 | + } |
| 38 | + delete(list) |
| 39 | + } |
| 40 | + Data :: struct { list:^[dynamic]Value, count:u8} |
| 41 | + data := Data{ &list, count} |
| 42 | + ForEach(hash,&data,proc(key:u64,value:^int,data:^Data) { |
| 43 | + append(data.list , Value{ decode(key,u32(data.count)), value^ }) |
| 44 | + }) |
| 45 | + slice.reverse_sort_by_key(list[:], proc(v:Value)->int{ return v.value }) |
| 46 | + for entry in list { |
| 47 | + fmt.printf("%s %.3f\n", entry.key, 100.0 * f64(entry.value) / f64(len(buf) - int(count) + 1)) |
| 48 | + } |
| 49 | + fmt.println() |
| 50 | +} |
| 51 | +count:: proc(buf:^string, entry: string) { |
| 52 | + hash := calculate(buf,cast(u32)len(entry)) |
| 53 | + defer delete_table(hash) |
| 54 | + data, ok:=Get(hash,encode(transmute([]u8)entry)) |
| 55 | + fmt.printf("%d\t%s\n",data^,entry) |
| 56 | +} |
| 57 | +work::proc { frequencies, count } |
| 58 | +hash_u64::proc(i:u64)->u64{ |
| 59 | + return i |
| 60 | +} |
| 61 | +equal_u64::proc(l,r:u64)->bool{ |
| 62 | + return l==r |
| 63 | +} |
| 64 | +calculate::proc(poly:^string, size: u32)->(rc:^HTable(u64,int)){ |
| 65 | + rc = makeTable(u64,int,hash_u64,equal_u64) |
| 66 | + frames:[FACTOR]A; |
| 67 | + threads:[FACTOR]^thread.Thread |
| 68 | + A :: struct { |
| 69 | + poly: ^string, |
| 70 | + size: u32, |
| 71 | + i: u32, |
| 72 | + hash: ^HTable(u64,int), |
| 73 | + } |
| 74 | + ex :: proc(self: ^A){ |
| 75 | + j := self.i |
| 76 | + for ;j < u32(len(self.poly)) +1 -self.size; j += FACTOR{ |
| 77 | + data,ok := Get(self.hash,encode(transmute([]u8)self.poly[j:j+self.size])) |
| 78 | + data^+=1 |
| 79 | + } |
| 80 | + } |
| 81 | + for frame,index in frames { |
| 82 | + frames[index] = { poly, size, u32(index), makeTable(u64,int,hash_u64,equal_u64) } |
| 83 | + threads[index] = thread.create_and_start_with_poly_data(&frames[index],ex) |
| 84 | + } |
| 85 | + for t,index in threads { |
| 86 | + thread.join(t) |
| 87 | + defer thread.destroy(t) |
| 88 | + ht := frames[index].hash |
| 89 | + defer delete_table(ht) |
| 90 | + ForEach(ht,rc,proc(key:u64,value:^int,rc:^HTable(u64,int)) { |
| 91 | + data,ok := Get(rc,key) |
| 92 | + data^+=value^ |
| 93 | + }) |
| 94 | + } |
| 95 | + return |
| 96 | +} |
| 97 | +read_lines_with_buffering :: proc() ->(string,io.Error){ |
| 98 | + r: bufio.Reader |
| 99 | + buffer: [1024]byte |
| 100 | + f,err:=os.open(os.args[1]) |
| 101 | + if err != os.ERROR_NONE { |
| 102 | + return "",io.Error(err) |
| 103 | + } |
| 104 | + defer os.close(f) |
| 105 | + bufio.reader_init_with_buf(&r, {os.stream_from_handle(f)}, buffer[:]) |
| 106 | + defer bufio.reader_destroy(&r) |
| 107 | + |
| 108 | + linerc:strings.Builder; |
| 109 | + strings.builder_init_none(&linerc); |
| 110 | + to_read :bool; |
| 111 | + for { |
| 112 | + line, err := bufio.reader_read_string(&r, '\n', context.allocator) |
| 113 | + defer delete(line, context.allocator) |
| 114 | + if err != nil { |
| 115 | + return strings.to_string(linerc),err |
| 116 | + } |
| 117 | + if !to_read && strings.has_prefix(line,`>THREE`) { |
| 118 | + to_read = true |
| 119 | + continue |
| 120 | + } |
| 121 | + if to_read { |
| 122 | + line = strings.trim_right(line, "\n") |
| 123 | + strings.write_string(&linerc,line) |
| 124 | + } |
| 125 | + } |
| 126 | +} |
| 127 | +Value::struct { |
| 128 | + key: string, |
| 129 | + value: int, |
| 130 | +} |
| 131 | +toChar :[256]rune |
| 132 | +toNum :[256]u8 |
| 133 | +initTables :: proc () { |
| 134 | + toNum['A'] = 0 |
| 135 | + toNum['C'] = 1 |
| 136 | + toNum['T'] = 2 |
| 137 | + toNum['G'] = 3 |
| 138 | + toNum['a'] = 0 |
| 139 | + toNum['c'] = 1 |
| 140 | + toNum['t'] = 2 |
| 141 | + toNum['g'] = 3 |
| 142 | + |
| 143 | + toChar[0] = 'A' |
| 144 | + toChar[1] = 'C' |
| 145 | + toChar[2] = 'T' |
| 146 | + toChar[3] = 'G' |
| 147 | +} |
| 148 | + |
| 149 | +encode :: proc (i : []u8)->u64 { |
| 150 | + rc: u64 |
| 151 | + for j in i { |
| 152 | + rc <<= 2 |
| 153 | + rc |= u64(toNum[j]) |
| 154 | + } |
| 155 | + return rc |
| 156 | +} |
| 157 | +decode::proc (i:u64,size:u32)->string { |
| 158 | + rc:strings.Builder; |
| 159 | + strings.builder_init_none(&rc); |
| 160 | + i := i |
| 161 | + for _ in 0..<size { |
| 162 | + strings.write_rune(&rc,toChar[i&3]) |
| 163 | + i >>= 2 |
| 164 | + } |
| 165 | + s := strings.to_string(rc) |
| 166 | + slice.reverse(transmute([]u8)s) |
| 167 | + return s |
| 168 | +} |
| 169 | +SIZE :: 1<<16 |
| 170 | +HTable :: struct(Key,Value:typeid) { |
| 171 | + table:[SIZE]^Node(Key,Value), |
| 172 | + hash: proc(k:Key)->u64, |
| 173 | + equal:proc(l,r:Key)->bool, |
| 174 | +} |
| 175 | +Node :: struct(Key,Value:typeid) { |
| 176 | + key: Key, |
| 177 | + value: Value, |
| 178 | + next:^Node(Key,Value), |
| 179 | +} |
| 180 | +makeTable :: proc($Key,$Value:typeid, hash: proc(k:Key)->u64,equal:proc(l,r:Key)->bool )->^HTable(Key,Value) { |
| 181 | + rc := new(HTable(Key,Value)) |
| 182 | + rc^ = {hash = hash,equal=equal} |
| 183 | + return rc |
| 184 | +} |
| 185 | +Get:: proc(input:^HTable($Key,$Value), key:Key)->(^Value,bool){ |
| 186 | + hash := input.hash(key) |
| 187 | + slot := hash & (SIZE-1) |
| 188 | + n := input.table[slot] |
| 189 | + if n == nil { |
| 190 | + n = new(Node(Key,Value)) |
| 191 | + n^ ={ key = key } |
| 192 | + input.table[slot] = n |
| 193 | + return &n.value,false |
| 194 | + } |
| 195 | + for ;n != nil;n=n.next { |
| 196 | + if input.equal(key,n.key) { |
| 197 | + return &n.value,true |
| 198 | + } |
| 199 | + } |
| 200 | + n = new(Node(Key,Value)) |
| 201 | + n^ ={ key = key, next=input.table[slot] } |
| 202 | + input.table[slot] = n |
| 203 | + return &n.value,false |
| 204 | +} |
| 205 | +ForEach::proc(input:^HTable($Key,$Value), data:^$T, f:proc(k:Key,v:^Value,data:^T)) { |
| 206 | + for n in &input.table { |
| 207 | + for ;n!=nil;n=n.next{ |
| 208 | + f(n.key,&n.value,data) |
| 209 | + } |
| 210 | + } |
| 211 | +} |
| 212 | +delete_table::proc(input:^HTable($Key,$Value)){ |
| 213 | + for n in &input.table { |
| 214 | + for n!=nil{ |
| 215 | + tmp := n |
| 216 | + n = n.next |
| 217 | + free(tmp) |
| 218 | + } |
| 219 | + } |
| 220 | + free(input) |
| 221 | +} |
0 commit comments