blob: 84ee928672e5a2947d69863c9184f90fd2bdef83 [file] [log] [blame]
peter klausler15fdae62018-01-30 19:47:171#ifndef FORTRAN_CHAR_BUFFER_H_
2#define FORTRAN_CHAR_BUFFER_H_
3
4// Defines a simple expandable buffer suitable for efficiently accumulating
5// a stream of bytes.
6
7#include <forward_list>
8#include <string>
9#include <utility>
10#include <vector>
11
12namespace Fortran {
13
14class CharBuffer {
15 public:
16 CharBuffer() {}
17 CharBuffer(CharBuffer &&that)
18 : blocks_(std::move(that.blocks_)), last_{that.last_},
19 bytes_{that.bytes_}, lastBlockEmpty_{that.lastBlockEmpty_} {
20 that.clear();
21 }
22 CharBuffer &operator=(CharBuffer &&that) {
23 blocks_ = std::move(that.blocks_);
24 last_ = that.last_;
25 bytes_ = that.bytes_;
26 lastBlockEmpty_ = that.lastBlockEmpty_;
27 that.clear();
28 return *this;
29 }
30
31 size_t bytes() const { return bytes_; }
32
33 void clear() {
34 blocks_.clear();
35 last_ = blocks_.end();
36 bytes_ = 0;
37 lastBlockEmpty_ = false;
38 }
39
40 char *FreeSpace(size_t *);
41 void Claim(size_t);
42 void Put(const char *data, size_t n);
43 void Put(const std::string &);
peter klausler15fdae62018-01-30 19:47:1744 void Put(char x) { Put(&x, 1); }
45 void CopyToContiguous(char *data);
46
47 private:
48 struct Block {
49 static constexpr size_t capacity{1 << 20};
50 char data[capacity];
51 };
52
53 public:
54 class iterator {
55 public:
56 iterator() {}
57 iterator(std::forward_list<Block>::const_iterator block, int offset)
58 : block_{block}, offset_{offset} {}
59 iterator(const iterator &that)
60 : block_{that.block_}, offset_{that.offset_} {}
61 iterator &operator=(const iterator &that) {
62 block_ = that.block_;
63 offset_ = that.offset_;
64 return *this;
65 }
66 const char &operator*() const { return block_->data[offset_]; }
67 iterator &operator++() {
68 if (++offset_ == Block::capacity) {
69 ++block_;
70 offset_ = 0;
71 }
72 return *this;
73 }
74 iterator operator++(int) {
75 iterator result{*this};
76 ++*this;
77 return result;
78 }
79 iterator &operator+=(size_t n) {
80 while (n >= Block::capacity - offset_) {
81 n -= Block::capacity - offset_;
82 offset_ = 0;
83 ++block_;
84 }
85 offset_ += n;
86 return *this;
87 }
88 bool operator==(const iterator &that) const {
89 return block_ == that.block_ && offset_ == that.offset_;
90 }
91 bool operator!=(const iterator &that) const {
92 return block_ != that.block_ || offset_ != that.offset_;
93 }
94 private:
95 std::forward_list<Block>::const_iterator block_;
96 int offset_;
97 };
98
99 iterator begin() const { return iterator(blocks_.begin(), 0); }
100 iterator end() const {
101 int offset = LastBlockOffset();
102 if (offset != 0 || lastBlockEmpty_) {
103 return iterator(last_, offset);
104 }
105 return iterator(blocks_.end(), 0);
106 }
107
108 private:
109 int LastBlockOffset() const { return bytes_ % Block::capacity; }
110 std::forward_list<Block> blocks_;
111 std::forward_list<Block>::iterator last_{blocks_.end()};
112 size_t bytes_{0};
113 bool lastBlockEmpty_{false};
114};
115} // namespace Fortran
116#endif // FORTRAN_CHAR_BUFFER_H_