[flang] Add char-buffer.{h,cc}.
authorpeter klausler <pklausler@nvidia.com>
Tue, 30 Jan 2018 19:47:17 +0000 (11:47 -0800)
committerpeter klausler <pklausler@nvidia.com>
Tue, 30 Jan 2018 19:47:17 +0000 (11:47 -0800)
Original-commit: flang-compiler/f18@14adb86568730f708ff4f5b85ef29c440a0b80b1

flang/char-buffer.cc [new file with mode: 0644]
flang/char-buffer.h [new file with mode: 0644]

diff --git a/flang/char-buffer.cc b/flang/char-buffer.cc
new file mode 100644 (file)
index 0000000..66be6eb
--- /dev/null
@@ -0,0 +1,61 @@
+#include "char-buffer.h"
+#include "idioms.h"
+#include <algorithm>
+#include <cstring>
+
+namespace Fortran {
+
+char *CharBuffer::FreeSpace(size_t *n) {
+  int offset{LastBlockOffset()};
+  if (blocks_.empty()) {
+    blocks_.emplace_front();
+    last_ = blocks_.begin();
+    lastBlockEmpty_ = true;
+  } else if (offset == 0 && !lastBlockEmpty_) {
+    last_ = blocks_.emplace_after(last_);
+    lastBlockEmpty_ = true;
+  }
+  *n = Block::capacity - offset;
+  return last_->data + offset;
+}
+
+void CharBuffer::Claim(size_t n) {
+  if (n > 0) {
+    bytes_ += n;
+    lastBlockEmpty_ = false;
+  }
+}
+
+void CharBuffer::Put(const char *data, size_t n) {
+  size_t chunk;
+  for (size_t at{0}; at < n; at += chunk) {
+    char *to{FreeSpace(&chunk)};
+    chunk = std::min(n - at, chunk);
+    Claim(chunk);
+    std::memcpy(to, data + at, chunk);
+  }
+}
+
+void CharBuffer::Put(const std::string &str) {
+  Put(str.data(), str.size());
+}
+
+void CharBuffer::Put(const std::vector<char> &data) {
+  size_t n{data.size()};
+  size_t chunk;
+  for (size_t at{0}; at < n; at += chunk) {
+    char *to{FreeSpace(&chunk)};
+    chunk = std::min(n - at, chunk);
+    Claim(chunk);
+    std::memcpy(to, &data[at], chunk);
+  }
+}
+
+void CharBuffer::CopyToContiguous(char *data) {
+  char *to{data};
+  for (char ch : *this) {
+    *to++ = ch;
+  }
+  CHECK(to == data + bytes_);
+}
+}  // namespace Fortran
diff --git a/flang/char-buffer.h b/flang/char-buffer.h
new file mode 100644 (file)
index 0000000..743bb24
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef FORTRAN_CHAR_BUFFER_H_
+#define FORTRAN_CHAR_BUFFER_H_
+
+// Defines a simple expandable buffer suitable for efficiently accumulating
+// a stream of bytes.
+
+#include <forward_list>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace Fortran {
+
+class CharBuffer {
+ public:
+  CharBuffer() {}
+  CharBuffer(CharBuffer &&that)
+    : blocks_(std::move(that.blocks_)), last_{that.last_},
+      bytes_{that.bytes_}, lastBlockEmpty_{that.lastBlockEmpty_} {
+    that.clear();
+  }
+  CharBuffer &operator=(CharBuffer &&that) {
+    blocks_ = std::move(that.blocks_);
+    last_ = that.last_;
+    bytes_ = that.bytes_;
+    lastBlockEmpty_ = that.lastBlockEmpty_;
+    that.clear();
+    return *this;
+  }
+
+  size_t bytes() const { return bytes_; }
+
+  void clear() {
+    blocks_.clear();
+    last_ = blocks_.end();
+    bytes_ = 0;
+    lastBlockEmpty_ = false;
+  }
+
+  char *FreeSpace(size_t *);
+  void Claim(size_t);
+  void Put(const char *data, size_t n);
+  void Put(const std::string &);
+  void Put(const std::vector<char> &);
+  void Put(char x) { Put(&x, 1); }
+  void CopyToContiguous(char *data);
+
+ private:
+  struct Block {
+    static constexpr size_t capacity{1 << 20};
+    char data[capacity];
+  };
+
+ public:
+  class iterator {
+   public:
+    iterator() {}
+    iterator(std::forward_list<Block>::const_iterator block, int offset)
+      : block_{block}, offset_{offset} {}
+    iterator(const iterator &that)
+      : block_{that.block_}, offset_{that.offset_} {}
+    iterator &operator=(const iterator &that) {
+      block_ = that.block_;
+      offset_ = that.offset_;
+      return *this;
+    }
+    const char &operator*() const { return block_->data[offset_]; }
+    iterator &operator++() {
+      if (++offset_ == Block::capacity) {
+        ++block_;
+        offset_ = 0;
+      }
+      return *this;
+    }
+    iterator operator++(int) {
+      iterator result{*this};
+      ++*this;
+      return result;
+    }
+    iterator &operator+=(size_t n) {
+      while (n >= Block::capacity - offset_) {
+        n -= Block::capacity - offset_;
+        offset_ = 0;
+        ++block_;
+      }
+      offset_ += n;
+      return *this;
+    }
+    bool operator==(const iterator &that) const {
+      return block_ == that.block_ && offset_ == that.offset_;
+    }
+    bool operator!=(const iterator &that) const {
+      return block_ != that.block_ || offset_ != that.offset_;
+    }
+   private:
+    std::forward_list<Block>::const_iterator block_;
+    int offset_;
+  };
+
+  iterator begin() const { return iterator(blocks_.begin(), 0); }
+  iterator end() const {
+    int offset = LastBlockOffset();
+    if (offset != 0 || lastBlockEmpty_) {
+      return iterator(last_, offset);
+    }
+    return iterator(blocks_.end(), 0);
+  }
+
+ private:
+  int LastBlockOffset() const { return bytes_ % Block::capacity; }
+  std::forward_list<Block> blocks_;
+  std::forward_list<Block>::iterator last_{blocks_.end()};
+  size_t bytes_{0};
+  bool lastBlockEmpty_{false};
+};
+}  // namespace Fortran
+#endif  // FORTRAN_CHAR_BUFFER_H_