Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

more/io/buffer.h

Go to the documentation of this file.
00001 //  Copyright (C) 2001  Petter Urkedal (petter.urkedal@matfys.lth.se)
00002 //
00003 //  This file is free software; you can redistribute it and/or modify
00004 //  it under the terms of the GNU General Public License as published by
00005 //  the Free Software Foundation; either version 2 of the License, or
00006 //  (at your option) any later version.
00007 //
00008 //  This file is distributed in the hope that it will be useful,
00009 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 //  GNU General Public License for more details.
00012 //
00013 //  You should have received a copy of the GNU General Public License
00014 //  along with this program; if not, write to the Free Software
00015 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00016 //
00017 //  As a special exception, you may use this file as part of a free
00018 //  software library without restriction.  Specifically, if other files
00019 //  instantiate templates or use macros or inline functions from this
00020 //  file, or you compile this file and link it with other files to
00021 //  produce an executable, this file does not by itself cause the
00022 //  resulting executable to be covered by the GNU General Public
00023 //  License.  This exception does not however invalidate any other
00024 //  reasons why the executable file might be covered by the GNU General
00025 //  Public License.
00026 //
00027 //  $Id: buffer.h,v 1.1 2002/05/30 18:01:37 petter_urkedal Exp $
00028 
00029 #include <more/io/readline.h>
00030 #include <more/gen/utility.h>
00031 #include <algorithm>
00032 #include <stdexcept>
00033 #include <cstdlib>
00034 
00035 
00036 #ifndef MORE_BUFFER_H
00037 #define MORE_BUFFER_H
00038 
00039 namespace more {
00040 namespace io {
00041 
00042   /** \class buffer buffer.h more/io/buffer.h
00043    **
00044    ** A stream buffer with arbitary lookahead.  The main purpose of
00045    ** this class is to provide arbitrary lookahead. This is done by a
00046    ** mechanism similar to the std::vector implementation, namely the
00047    ** buffer space is at least doubled each time it need to be
00048    ** expanded, in order to provide amortized constant operations.
00049    ** This buffer can be used for both input and output, though
00050    ** usually not at the same time. An exception could be duplex
00051    ** sound, since in that case, the length of the output is the same
00052    ** as that of the input.  Due to the buffering, the overhead of
00053    ** having both input and output when only one is used is
00054    ** negligible. */
00055   template<typename T>
00056     struct buffer : gen::noncopyable
00057     {
00058         typedef std::size_t size_type;
00059         typedef std::ptrdiff_t difference;
00060         typedef T value_type;
00061 
00062         /** The item source interface. */
00063         struct driver
00064         {
00065             typedef buffer::difference difference;
00066             typedef buffer::size_type size_type;
00067             typedef buffer::value_type value_type;
00068 
00069             /** Overload to provide input. If overloaded this function
00070              * shall shall fill a range [first, stop), where first <= stop
00071              * < last, with items and return stop.  Return 0 to indicate
00072              * end of input.  The default is to return last, which gives a
00073              * infinite sequence of junk (default constructed, or
00074              * previously assigned) elements, which is suitable for a pure
00075              * output stream. */
00076             virtual T* read(T* first, T* last) { return last; }
00077 
00078             /** Overload to receive output. If overloaded write [first, last)
00079              * to the tied output channel. The default is to do nothing, which
00080              * is suitable for a pure input stream. */
00081             virtual void write(T* first, T* last) {}
00082 
00083             /** Shall return true on error. */
00084             virtual bool is_error() { return false; }
00085 
00086             virtual ~driver() {}
00087         };
00088 
00089       private:
00090         static size_type const n_buf_init = 512;
00091 
00092       public:
00093         /** Construct an optionally install a driver.  If \a
00094             is_interactive is true, the buffer will not read more
00095             characters from the driver than strictly requested. */
00096         explicit buffer(driver* drv = 0, bool is_interactive = false)
00097             : m_drv(drv? drv : new driver),
00098               m_alloc(0), m_begin(0), m_cur(0), m_stop(0), m_end(0),
00099               have_eof(false)/*, m_super(0)*/,
00100               m_is_interactive(is_interactive)
00101         {
00102             lookahead(1);
00103         }
00104 
00105         /** Deletes the tied driver and destructs the buffer. */
00106         ~buffer()
00107         {
00108             sync();
00109             delete[] m_alloc;
00110             delete m_drv;
00111 //          delete m_super;
00112         }
00113 
00114 //      void push(driver* drv) {
00115 //          buffer* b = new buffer(drv);
00116 //          swap(*b);
00117 //          m_super = b;
00118 //      }
00119 
00120 //      void pop() {
00121 //          if (!m_super)
00122 //              throw std::logic_error("This is the toplevel buffer.");
00123 //          buffer* b = m_super;
00124 //          swap(*b);
00125 //          delete b;
00126 //      }
00127 
00128         /** Sync and clears the buffer and ties the buffer to the given driver.
00129          * The remaining output sequence is first written, and any unread
00130          * input is discarded as the buffer is reset.  Then the old driver
00131          * is returns and must be deleted by the callee, and the new driver
00132          * installed. */
00133         driver* install(driver* b)
00134         {
00135             driver* old = m_drv;
00136             this->~buffer();
00137             new ((void*)this) buffer(b);
00138             return old;
00139         }
00140 
00141         /** Write out any buffered characters. */
00142         void sync() {
00143             if (m_begin != m_cur)
00144                 m_drv->write(m_begin, m_cur);
00145         }
00146 
00147         /** Returns a reference to item number \a n counting from the
00148          *  current position, with no checks.
00149          *  \pre There is at least n+1 items lookahead. */
00150         T& at(size_type n) { return m_cur[n]; }
00151         T const& at(size_type n) const { return m_cur[n]; }
00152 
00153         /** Returns a pointer to the current buffer position, with no checks.
00154          *  It is valid to dereference any element within the current lookahead.
00155          *  The pointer is invalidated by a call to any non-const method which
00156          *  is not also overloaded with a const method. */
00157         T* data() { return m_cur; }
00158         T const* data() const { return m_cur; }
00159 
00160         /** Returns an array of at least \a n items starting at the
00161          *  current item.
00162          *  \pre There is at least \a n items left in the input sequence. */
00163         T* data(size_type n)
00164         {
00165             if (lookahead(n) >= n)
00166                 return m_cur;
00167             else
00168                 throw std::length_error("more::io::buffer::data: "
00169                                         "Too few items in input sequence.");
00170         }
00171 
00172         /** Get \a n items in the form of an array.
00173          *  That is, advance the current position with \a n, and return a
00174          *  pointer to the start of the region advanced over.
00175          *  \pre There is at least \a n items left in the input sequence.
00176          *  \post there is at least 1 item lookahead unless \c is_eof(). */
00177         T* get_n(size_type n)
00178         {
00179             if (lookahead(n+1) >= n) {
00180                 m_cur += n;
00181                 return m_cur - n;
00182             }
00183             else
00184                 throw std::length_error("more::io::buffer::data: "
00185                                         "Too few items in input sequence.");
00186         }
00187 
00188         /** Increment the current position and return reference to the
00189          *  new previous item.
00190          *  \pre \c !is_eof()
00191          *  \post It is guaranteed to be one character lookahead so that
00192          *  peek() is valid, unless is_eof(). */
00193         T& get()
00194         {
00195             if (lookahead(2) < 1)
00196                 throw std::length_error("more::io::buffer::get: "
00197                                         "Too few items in input sequence.");
00198             ++m_cur;
00199             return m_cur[-1];
00200         }
00201 
00202         /** Returns a reference to the current item without incrementing it.
00203          *  \pre is_eof() is false.
00204          */
00205         T& peek() { return *m_cur; }
00206         T const& peek() const { return *m_cur; }
00207 
00208         /** Attemt to assure at least n items lookahead, returns the actual
00209          * number. */
00210         size_type lookahead(size_type n)
00211         {
00212             if (m_cur + n > m_stop)
00213                 extend(n);
00214             return m_stop - m_cur;
00215         }
00216 
00217         /** Returns true if the buffer is tied to an input function,
00218          * and there is no more input. */
00219         bool is_eof() { return m_cur >= m_stop; }
00220 
00221         /** True if the driver says so. */
00222         bool is_error() { return m_drv->is_error(); }
00223 
00224         /** Swaps drivers, contents and states of the two buffers. */
00225         void swap(buffer& b)
00226         {
00227             std::iter_swap(m_drv, b.m_drv);
00228             std::iter_swap(m_alloc, b.m_alloc);
00229             std::iter_swap(m_begin, b.m_begin);
00230             std::iter_swap(m_cur, b.m_cur);
00231             std::iter_swap(m_stop, b.m_stop);
00232             std::iter_swap(m_end, b.m_end);
00233             std::swap(have_eof, b.have_eof);
00234 //          std::swap(m_super, b.m_super);
00235         }
00236 
00237       protected:
00238         /** Set a fixed buffer. If the buffer provides input, it is assumed
00239          * that the range provided already contains a bufferfull of data. */
00240         void set_fixed(T* first, T* end, bool have_eof = false)
00241         {
00242             delete[] m_alloc;
00243             m_alloc = 0;
00244             m_begin = first;
00245             m_cur = first;
00246             m_stop = end;
00247             m_end = end;
00248             if (have_eof) ++m_end;
00249         }
00250 
00251       private:
00252         void extend(size_type n);
00253 
00254         driver* m_drv;
00255         T* m_alloc;
00256         T* m_begin;
00257         T* m_cur;
00258         T* m_stop;
00259         T* m_end;
00260         bool have_eof;
00261 //      buffer* m_super;
00262         bool m_is_interactive;
00263     };
00264 
00265   template<typename Char, typename Traits>
00266     typename buffer<Char>::driver*
00267     new_isdriver(std::basic_string<Char, Traits> const& str, bool want_eof);
00268 
00269   template<typename Char, typename Traits>
00270     typename buffer<Char>::driver*
00271     new_osdriver(std::basic_string<Char, Traits>& str);
00272 
00273   /** Allocates a driver for input from the file with named name, or
00274       stdin if name=0. */
00275   template<typename Char>
00276     typename buffer<Char>::driver*
00277     new_ifdriver(char const* name, bool want_eof);
00278 
00279   /** Allocates a driver for output to file named name. */
00280   template<typename Char>
00281     typename buffer<Char>::driver*
00282     new_ofdriver(char const* name);
00283 
00284   template<typename Char>
00285     struct readline_driver {};
00286 
00287   template<>
00288     struct readline_driver<char> : buffer<char>::driver
00289     {
00290         readline_driver(char* prompt, bool want_eof, char* sep = "\n");
00291         ~readline_driver();
00292         void set_prompt(char* prompt) { m_prompt = prompt; }
00293       protected:
00294         char* read(char* first, char* last);
00295       private:
00296         char* m_prompt;
00297         char* m_pending;
00298         bool m_want_eof;
00299         char* m_sep;
00300         bool m_toggle;
00301     };
00302 
00303   template<>
00304     struct readline_driver<wchar_t> : buffer<wchar_t>::driver
00305     {
00306         readline_driver(char* prompt, bool want_eof, wchar_t* sep = L"\n");
00307         ~readline_driver();
00308         void set_prompt(char* prompt) { m_prompt = prompt; }
00309       protected:
00310         wchar_t* read(wchar_t* first, wchar_t* last);
00311       private:
00312         char* m_prompt;
00313         wchar_t* m_pending;
00314         wchar_t* m_alloc;
00315         bool m_want_eof;
00316         wchar_t* m_sep;
00317         bool m_toggle;
00318     };
00319 
00320   /** Return a readline driver for a buffer.  This is the same as the
00321    *  other overload with <tt>sep = "\n"</tt> or <tt>sep = L"\n"</tt>
00322    *  as appropriate. */
00323   template<typename Char>
00324     inline typename buffer<Char>::driver*
00325     new_readline_driver(char* prompt, bool want_eof = false)
00326     {
00327         return new readline_driver<Char>(prompt, want_eof);
00328     }
00329 
00330   /** Return readline driver for a buffer.  A \a sep is inserted in
00331    *  front of each line, including the first.  Reading over these
00332    *  characters causes a prompt.  \a sep is typically a newline, and
00333    *  serve as dummy lookahead character(s) which allows the prompt to
00334    *  be delayed until the program skips over white-spaces for the
00335    *  purpose of reading something.  The driver will be free by the
00336    *  buffer.  */
00337   template<typename Char>
00338     inline typename buffer<Char>::driver*
00339     new_readline_driver(char* prompt, bool want_eof, Char* sep)
00340     {
00341         return new readline_driver<Char>(prompt, want_eof, sep);
00342     }
00343 
00344 }}
00345 
00346 #include <more/bits/buffer.tcc>
00347 
00348 #endif

Generated on Sat Sep 7 19:11:15 2002 for more with Doxygen 1.2.13.1. Doxygen 1.2.13.1 is written and copyright 1997-2002 by Dimitri van Heesch.