buf_stream.hh

00001 // This file is a part of Aurelia.
00002 // Copyright (C) 2010  Valentin David
00003 // Copyright (C) 2010  University of Bergen
00004 //
00005 // This program is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 
00018 #ifndef __BUF_STREAM_HH
00019 # define __BUF_STREAM_HH
00020 
00021 # include <forward_list>
00022 # include <istream>
00023 # include <sstream>
00024 # include "hash/hash_addr.hh"
00025 
00026 namespace aurelia {
00027 
00028 struct rc_char {
00029   int refs;
00030   char c;
00031   rc_char(char c): refs(0), c(c){}
00032   rc_char(const rc_char& other): refs(other.refs), c(other.c) {}
00033 };
00034 
00035 struct buf_stream;
00036 
00037 struct buf_stream_iterator {
00038 private:
00039   buf_stream* s;
00040   std::forward_list<rc_char>::iterator i;
00041   int pos;
00042 
00043   friend class buf_stream;
00044   explicit buf_stream_iterator(buf_stream* s,
00045                                const std::forward_list<rc_char>::iterator& i,
00046                                int pos);
00047 public:
00048   unsigned hash() const;
00049 
00050   int get_pos() const {
00051     return pos;
00052   }
00053 
00054   bool operator==(const buf_stream_iterator& other) const;
00055 
00056   bool operator!=(const buf_stream_iterator& other) const {
00057     return !(*this == other);
00058   }
00059 
00060   bool operator<(const buf_stream_iterator& other) const {
00061     return pos < other.pos;
00062   }
00063 
00064   ~buf_stream_iterator();
00065 
00066   buf_stream_iterator& operator++();
00067 
00068   buf_stream_iterator(const buf_stream_iterator&);
00069   buf_stream_iterator(buf_stream_iterator&&);
00070 
00071   char operator*() const {
00072     return (*i).c;
00073   }
00074 
00075   bool eof() const;
00076 
00077   buf_stream_iterator& operator=(const buf_stream_iterator& other) {
00078     return *this = buf_stream_iterator(other);
00079   }
00080 
00081   buf_stream_iterator& operator=(buf_stream_iterator&& other);
00082 
00083   bool eat(const std::string& s) {
00084     std::string::const_iterator i = s.begin();
00085     buf_stream_iterator t(*this);
00086     while (!t.eof() && (i != s.end())) {
00087       if (*i != *t)
00088         return false;
00089       ++i;
00090       ++t;
00091     }
00092     if (i != s.end())
00093       return false;
00094     *this = t;
00095     return true;
00096   }
00097 };
00098 
00099 struct buf_stream {
00100 private:
00101   std::istream* real_stream;
00102   std::forward_list<rc_char> buf;
00103   int start;
00104   unsigned _hash;
00105 #ifndef NDEBUG
00106   int size;
00107 #endif
00108 
00109 public:
00110   buf_stream(const buf_stream&) = delete;
00111   buf_stream(buf_stream&&) = delete;
00112 
00113 #ifndef NDEBUG
00114   int buffer_start() const {
00115     return start;
00116   }
00117 
00118   //Testing method
00119   int buffer_size() const {
00120     return size;
00121   }
00122 #endif
00123 
00124   explicit buf_stream(std::istream& s): real_stream(&s)
00125                                       , start(0)
00126 #ifndef NDEBUG
00127                                       , size(0)
00128 #endif
00129   {
00130     _hash = hash_addr(s);
00131   }
00132 
00133   unsigned hash() const {
00134     return _hash;
00135   }
00136 
00137   buf_stream& operator=(const buf_stream&) = delete;
00138   buf_stream& operator=(buf_stream&&) = delete;
00139 
00140   buf_stream_iterator begin() {
00141     std::forward_list<rc_char>::iterator i = buf.begin();
00142     if (i == buf.end()) {
00143       char c = real_stream->get();
00144 #ifndef NDEBUG
00145       size++,
00146 #endif
00147       buf.push_front(rc_char(c));
00148     }
00149     return buf_stream_iterator(this, buf.begin(), start);
00150   }
00151 
00152   buf_stream_iterator end() {
00153     std::forward_list<rc_char>::iterator i = buf.end();
00154     return buf_stream_iterator(this, i, -1);
00155   }
00156 
00157   std::forward_list<rc_char>::iterator buf_end() {
00158     return buf.end();
00159   }
00160 
00161   void cleanup () {
00162     std::forward_list<rc_char>::iterator i = buf.begin();
00163     while (i != buf.end()) {
00164       if ((*i++).refs == 0) {
00165         start++;
00166 #ifndef NDEBUG
00167         size--;
00168 #endif
00169         buf.pop_front();
00170       }
00171       else return ;
00172     }
00173   }
00174 
00175   bool is_end(const std::forward_list<rc_char>::iterator& i) const {
00176     return i == buf.end();
00177   }
00178 
00179   void next(std::forward_list<rc_char>::iterator& i) {
00180     std::forward_list<rc_char>::iterator next = i;
00181     ++next;
00182     if (next == buf.end()) {
00183       char c = real_stream->get();
00184       if (!real_stream->good()) {
00185         i = next;
00186         return ;
00187       }
00188       buf.insert_after(i,rc_char(c));
00189 #ifndef NDEBUG
00190       size++;
00191 #endif
00192       ++i;
00193       return ;
00194     }
00195     i = next;
00196   }
00197 };
00198 
00199 buf_stream_iterator::buf_stream_iterator(buf_stream* s,
00200                                          const std::forward_list<rc_char>
00201                                          ::iterator& i, int pos)
00202   : s(s), i(i), pos(pos) {
00203   if (pos != -1)
00204     (*i).refs++;
00205 }
00206 buf_stream_iterator::buf_stream_iterator(const buf_stream_iterator& other)
00207   : s(other.s), i(other.i), pos(other.pos) {
00208   if (!(s->is_end(i)))
00209     (*i).refs++;
00210 }
00211 
00212   buf_stream_iterator::buf_stream_iterator(buf_stream_iterator&& other)
00213   : s(other.s), i(s->buf_end()), pos(other.pos) {
00214   std::swap(i, other.i);
00215   other.pos = -1;
00216   }
00217 
00218 buf_stream_iterator::~buf_stream_iterator()
00219 {
00220   if (!s->is_end(i)) {
00221     if (--((*i).refs) == 0)
00222       s->cleanup();
00223   }
00224 }
00225 
00226 buf_stream_iterator& buf_stream_iterator::operator++() {
00227   std::forward_list<rc_char>::iterator prev(i);
00228   s->next(i);
00229   pos++;
00230   if (!s->is_end(i)) {
00231     (*i).refs++;
00232   }
00233   if (--((*prev).refs) == 0)
00234     s->cleanup();
00235   return *this;
00236 }
00237 
00238 bool buf_stream_iterator::eof() const {
00239   return (s->is_end(i));
00240 }
00241 
00242   buf_stream_iterator& buf_stream_iterator::operator=
00243   (buf_stream_iterator&& other) {
00244     std::swap(s, other.s);
00245     std::swap(pos, other.pos);
00246     std::swap(i, other.i);
00247     return *this;
00248   }
00249 
00250 unsigned buf_stream_iterator::hash() const {
00252   unsigned hash = (unsigned)pos;
00253   hash = (hash << 11) | (hash >> 21);
00254   hash ^= s->hash();
00255   return hash;
00256 }
00257 
00258 bool buf_stream_iterator::operator==(const buf_stream_iterator& other) const {
00259   if (pos == -1) {
00260     return s->is_end(other.i);
00261   }
00262   if (other.pos == -1) {
00263     return s->is_end(i);
00264   }
00265   return (s == other.s) && (pos == other.pos);
00266 }
00267 
00268 typedef buf_stream_iterator stream;
00269 
00270   std::string stream_range_to_string(stream begin, const stream& end) {
00271     std::stringstream ret;
00272     while (begin != end) {
00273       ret << *begin;
00274       ++begin;
00275     }
00276     return ret.str();
00277   }
00278 
00279   template <typename Stream>
00280   Stream& operator<<(Stream& s, const stream& i) {
00281     s << "(stream:" <<  i.get_pos() << ")";
00282     return s;
00283   }
00284 }
00285 
00286 #endif