00001
00002
00003
00004 #ifndef UTIL_FILE_STREAM_H
00005 #define UTIL_FILE_STREAM_H
00006
00007 #include "util/fake_ostream.hh"
00008 #include "util/file.hh"
00009 #include "util/scoped.hh"
00010
00011 #include <cassert>
00012 #include <cstring>
00013
00014 #include <stdint.h>
00015
00016 namespace util {
00017
00018 class FileStream : public FakeOStream<FileStream> {
00019 public:
00020 FileStream(int out = -1, std::size_t buffer_size = 8192)
00021 : buf_(util::MallocOrThrow(std::max<std::size_t>(buffer_size, kToStringMaxBytes))),
00022 current_(static_cast<char*>(buf_.get())),
00023 end_(current_ + std::max<std::size_t>(buffer_size, kToStringMaxBytes)),
00024 fd_(out) {}
00025
00026 ~FileStream() {
00027 flush();
00028 }
00029
00030 void SetFD(int to) {
00031 flush();
00032 fd_ = to;
00033 }
00034
00035 FileStream &flush() {
00036 if (current_ != buf_.get()) {
00037 util::WriteOrThrow(fd_, buf_.get(), current_ - (char*)buf_.get());
00038 current_ = static_cast<char*>(buf_.get());
00039 }
00040 return *this;
00041 }
00042
00043
00044 FileStream &write(const void *data, std::size_t length) {
00045 if (UTIL_LIKELY(current_ + length <= end_)) {
00046 std::memcpy(current_, data, length);
00047 current_ += length;
00048 return *this;
00049 }
00050 flush();
00051 if (current_ + length <= end_) {
00052 std::memcpy(current_, data, length);
00053 current_ += length;
00054 } else {
00055 util::WriteOrThrow(fd_, data, length);
00056 }
00057 return *this;
00058 }
00059
00060 FileStream &seekp(uint64_t to) {
00061 flush();
00062 util::SeekOrThrow(fd_, to);
00063 return *this;
00064 }
00065
00066 protected:
00067 friend class FakeOStream<FileStream>;
00068
00069 char *Ensure(std::size_t amount) {
00070 if (UTIL_UNLIKELY(current_ + amount > end_)) {
00071 flush();
00072 assert(current_ + amount <= end_);
00073 }
00074 return current_;
00075 }
00076
00077 void AdvanceTo(char *to) {
00078 current_ = to;
00079 assert(current_ <= end_);
00080 }
00081
00082 private:
00083 util::scoped_malloc buf_;
00084 char *current_, *end_;
00085 int fd_;
00086 };
00087
00088 }
00089
00090 #endif