diff --git a/pkg/wc/complex-counter.go b/pkg/wc/complex-counter.go new file mode 100644 index 0000000..ecc431f --- /dev/null +++ b/pkg/wc/complex-counter.go @@ -0,0 +1,58 @@ +package wc + +import ( + "bytes" + "unicode" +) + +type ComplexCount struct { + CharCount int64 + WordCount int64 + LineCount int64 + MaxLineLength int64 +} + +func GetComplexCount(chunk []byte) ComplexCount { + var count = ComplexCount{} + word := false + var lineLength int64 + runes := bytes.Runes(chunk) + for _, b := range runes { + count.CharCount++ + if b == '\n' { + if lineLength > count.MaxLineLength { + count.MaxLineLength = lineLength + } + lineLength = 0 + count.LineCount++ + if word { + word = false + count.WordCount++ + } + } else if unicode.IsSpace(b) { + lineLength++ + if word { + word = false + count.WordCount++ + } + } else { + lineLength++ + word = true + } + } + return count +} + +func ConcurrentComplexChunkCounter(chunks <-chan []byte, counts chan<- ComplexCount) { + var totalCount ComplexCount + for chunk := range chunks { + count := GetComplexCount(chunk) + totalCount.CharCount += count.CharCount + totalCount.WordCount += count.WordCount + totalCount.LineCount += count.LineCount + if count.MaxLineLength > totalCount.MaxLineLength { + totalCount.MaxLineLength = count.MaxLineLength + } + } + counts <- totalCount +} diff --git a/pkg/wc/counter.go b/pkg/wc/counter.go index ef191b9..7a8125c 100644 --- a/pkg/wc/counter.go +++ b/pkg/wc/counter.go @@ -31,79 +31,108 @@ func Count(filename string, cw, cc, cl, cb, mll bool) { return } defer file.Close() - fi, err := file.Stat() - if err != nil { - fmt.Println(err) - return - } - size := fi.Size() processLine := cw || cc var c = &Counter{} numWorkers := runtime.NumCPU() - chunks := make(chan []byte, numWorkers) - counts := make(chan int64, numWorkers) - - for i := 0; i < numWorkers; i++ { - go ConcurrentChunkCounter(chunks, counts) - } - if cl && !processLine { - for { - buf := make([]byte, BufferSize) - bytes, err := file.Read(buf) - chunks <- buf[:bytes] - if err != nil { - if err == io.EOF { - break - } else { - panic(err) - } - } - } - close(chunks) - for i := 0; i < numWorkers; i++ { - c.Lines += <-counts - } - close(counts) + c.Lines = CountLines(file, numWorkers) + } else { + + c = CountComplex(file, numWorkers) } if cb { - c.Bytes = size + fi, err := file.Stat() + if err != nil { + fmt.Println(err) + return + } + c.Bytes = fi.Size() } - if c.Lines > 0 { + if cl { fmt.Printf("%d ", c.Lines) } - if c.Words > 0 { + if cw { fmt.Printf("%d ", c.Words) } - if c.Chars > 0 { + if cc { fmt.Printf("%d ", c.Words) } - if c.Bytes > 0 { + if cb { fmt.Printf("%d ", c.Bytes) } - if c.MaxLineLength > 0 { + if mll { fmt.Printf("%d ", c.MaxLineLength) } fmt.Printf("%s\n", filename) } -//func (c *Counter) CountLines() { -// for { -// _, p, err := c.FileReader.ReadLine() -// if err != nil && err != io.EOF { -// panic(err) -// } -// if err == io.EOF { -// break -// } -// if !p { -// c.Lines++ -// } -// } -// c.Lines-- -//} +func CountLines(file *os.File, numWorkers int) int64 { + var lines int64 + + chunks := make(chan []byte, numWorkers) + counts := make(chan int64, numWorkers) + + for i := 0; i < numWorkers; i++ { + go ConcurrentChunkCounter(chunks, counts) + } + + for { + buf := make([]byte, BufferSize) + bytes, err := file.Read(buf) + chunks <- buf[:bytes] + if err != nil { + if err == io.EOF { + break + } else { + panic(err) + } + } + } + close(chunks) + for i := 0; i < numWorkers; i++ { + lines += <-counts + } + close(counts) + return lines +} + +func CountComplex(file *os.File, numWorkers int) *Counter { + counter := Counter{} + + chunks := make(chan []byte, numWorkers) + counts := make(chan ComplexCount, numWorkers) + + for i := 0; i < numWorkers; i++ { + go ConcurrentComplexChunkCounter(chunks, counts) + } + + for { + buf := make([]byte, BufferSize) + count, err := file.Read(buf) + chunks <- buf[:count] + if err != nil { + if err == io.EOF { + break + } else { + panic(err) + } + } + } + close(chunks) + for i := 0; i < numWorkers; i++ { + count := <-counts + counter.Lines += count.LineCount + counter.Words += count.WordCount + counter.Chars += count.CharCount + if count.MaxLineLength > counter.MaxLineLength { + counter.MaxLineLength = count.MaxLineLength + } + } + close(counts) + return &counter +} diff --git a/pkg/wc/chunk.go b/pkg/wc/line-counter.go similarity index 100% rename from pkg/wc/chunk.go rename to pkg/wc/line-counter.go