1da39c979SShuo Chen#pragma once
2da39c979SShuo Chen
3da39c979SShuo Chen#include <string>
4da39c979SShuo Chen#include <fcntl.h>
5da39c979SShuo Chen
6da39c979SShuo Chenclass SegmentInput
7da39c979SShuo Chen{
8da39c979SShuo Chen public:
9da39c979SShuo Chen  explicit SegmentInput(const char* filename, int bufsize=kBufferSize)
10da39c979SShuo Chen    : filename_(filename),
11da39c979SShuo Chen      fd_(::open(filename, O_RDONLY)),
12da39c979SShuo Chen      buffer_size_(bufsize),
13da39c979SShuo Chen      data_(new char[buffer_size_])
14da39c979SShuo Chen  {
15da39c979SShuo Chen    refill();
16da39c979SShuo Chen  }
17da39c979SShuo Chen
18da39c979SShuo Chen  const std::string& filename() const { return filename_; }
19da39c979SShuo Chen  int64_t tell() const { return offset_; }
20da39c979SShuo Chen  const std::string& current_word() const { return word_; }
21da39c979SShuo Chen  int64_t current_count() const { return count_; }
22da39c979SShuo Chen
23da39c979SShuo Chen  bool next()
24da39c979SShuo Chen  {
25da39c979SShuo Chen    if (avail_ <= 0)
26da39c979SShuo Chen      return false;
27da39c979SShuo Chen    char* nl = static_cast<char*>(::memchr(start_, '\n', avail_));
28da39c979SShuo Chen    if (nl)
29da39c979SShuo Chen    {
30da39c979SShuo Chen      char* tab = static_cast<char*>(::memchr(start_, '\t', nl - start_));
31da39c979SShuo Chen      if (tab)
32da39c979SShuo Chen      {
33da39c979SShuo Chen        count_ = strtol(tab+1, NULL, 10);
34da39c979SShuo Chen        word_ = std::string_view(start_, tab-start_);
35da39c979SShuo Chen
36da39c979SShuo Chen        int len = nl - start_ + 1;
37da39c979SShuo Chen        avail_ -= len;
38da39c979SShuo Chen        offset_ += len;
39da39c979SShuo Chen        assert(avail_ >= 0);
40da39c979SShuo Chen        if (avail_ == 0)
41da39c979SShuo Chen        {
42da39c979SShuo Chen          refill();
43da39c979SShuo Chen        }
44da39c979SShuo Chen        else
45da39c979SShuo Chen        {
46da39c979SShuo Chen          start_ += len;
47da39c979SShuo Chen        }
48da39c979SShuo Chen        return true;
49da39c979SShuo Chen      }
50da39c979SShuo Chen      else
51da39c979SShuo Chen      {
52da39c979SShuo Chen        avail_ = 0;
53da39c979SShuo Chen        assert(0);
54da39c979SShuo Chen        return false;
55da39c979SShuo Chen      }
56da39c979SShuo Chen    }
57da39c979SShuo Chen    else
58da39c979SShuo Chen    {
59da39c979SShuo Chen      refill();
60da39c979SShuo Chen      return next();
61da39c979SShuo Chen    }
62da39c979SShuo Chen  }
63da39c979SShuo Chen
64da39c979SShuo Chen private:
65da39c979SShuo Chen  void refill()
66da39c979SShuo Chen  {
67da39c979SShuo Chen    start_ = data_.get();
68da39c979SShuo Chen    avail_ = ::pread(fd_, start_, buffer_size_, offset_);
69da39c979SShuo Chen  }
70da39c979SShuo Chen
71da39c979SShuo Chen  const std::string filename_;
72da39c979SShuo Chen  const int fd_;
73da39c979SShuo Chen  const int buffer_size_;
74da39c979SShuo Chen  int64_t offset_ = 0;  // file position
75da39c979SShuo Chen
76da39c979SShuo Chen  char* start_ = nullptr;
77da39c979SShuo Chen  int avail_ = 0;
78da39c979SShuo Chen  std::unique_ptr<char[]> data_;
79da39c979SShuo Chen
80da39c979SShuo Chen  std::string word_;
81da39c979SShuo Chen  int64_t count_ = 0;
82da39c979SShuo Chen
83da39c979SShuo Chen  SegmentInput(const SegmentInput&) = delete;
84da39c979SShuo Chen  void operator=(const SegmentInput&) = delete;
85da39c979SShuo Chen};
86da39c979SShuo Chen
87da39c979SShuo Chen
88