root/trunk/whisperlib/common/io/buffer/memory_stream.h

Revision 7, 10.8 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Catalin Popescu
31
32 #ifndef __COMMON_IO_BUFFER_MEMORY_STREAM_H__
33 #define __COMMON_IO_BUFFER_MEMORY_STREAM_H__
34
35 #include <sys/uio.h>
36
37 #include <utility>
38 #include <string>
39 #include <vector>
40
41 #include <whisperlib/common/base/types.h>
42 #include <whisperlib/common/io/buffer/data_block.h>
43 #include <whisperlib/common/io/num_streaming.h>
44
45 namespace io {
46
47 class MemoryStream {
48  public:
49   MemoryStream(common::ByteOrder byte_order = common::kByteOrder,
50                BlockSize block_size = DataBlock::kDefaultBufferSize);
51   ~MemoryStream();
52
53   common::ByteOrder byte_order() const { return byte_order_; }
54
55   //////////////////////////////////////////////////////////////////////
56   //
57   // "FAST" interface - works mostly by actioning on the underneath
58   //                    data buffers and moving them around.
59   //
60
61   // Appends a raw block to the buffer - creates a new block and
62   // calls AppendBlock
63   // The block becomes ours and is integrated in a new DataBlock.
64   // The data should be deletable (e.g. is OK to do delete [] data)
65   // NEVER - AppendRaw the same buffer to two MemoryStreams !! (instead
66   // append to one temp buffer and use AppendStream /
67   // AppendStreamNonDestructive)
68   void AppendRaw(const char* data, int32 size,
69                  util::FreeArrayList<char>* disposer = NULL);
70
71   // Appends this block to our internal list (increments the reference
72   // count)
73   void AppendBlock(DataBlock* data);
74
75   // Returns a piece of data from the buffer and advances the read.
76   // If not 0, *size may specify the maximum ammount ot be read..
77   // Retruns false on end-of-buffer.
78   bool ReadNext(const char** buffer, int32* size);
79
80   // Reads all the internal buffers for a writev operation
81   int32 ReadForWritev(struct ::iovec** iov, int* iovcnt, int32 max_size);
82
83   // Returns a piece of buffer already allocated and ready to be written to
84   // (it is reserved and considered written). Use ConfirmScratch to confirm
85   // how much you used from returned size.
86   // IMPORTANT NOTE: after a GetScratchSpace the next operation w/ this
87   //                 stream must be ConfirmScratch !!!
88   void GetScratchSpace(char** buffer, int32* size);
89   void ConfirmScratch(int32 size);
90
91   // Returns true if the buffer is empty.
92   bool IsEmpty() const {
93     return size_ <= 0;
94   }
95
96   // Returns the total amount of data in the buffer
97   int32 Size() const {
98     return size_;
99   }
100
101   // Appends a portion of the given data block to our list (makes a copy)
102   // in a fresh new block..
103   void AppendNewBlock(DataBlock* data,
104                       BlockSize pos_begin, BlockSize pos_end);
105
106   //////////////////////////////////////////////////////////////////////
107   //
108   // "MEDIUM" inteface functions - these may take a long time, or a small
109   //                               time, depending on conditions..
110
111   // Appends a full buffer to this one -
112   void AppendStream(MemoryStream* buffer, int32 size = -1);
113
114   // Appends without destroying the buffer - appends just size bytes
115   // (or the entire buffer if size == -1)
116   void AppendStreamNonDestructive(const MemoryStream* buffer,
117                                   int32 size = -1);
118
119   //////////////////////////////////////////////////////////////////////
120   //
121   // "SLOWER" inteface functions - these may take longer as they involve
122   //                               data copying and buffer allocation
123
124   // Reads "len" bytes of data into the given "buffer".
125   // Returns the number of bytes read. Can be less than "len" if less bytes
126   // are available.
127   int32 Read(void* buffer, int32 len) {
128     if ( len == 0 ) return 0;
129     return ReadInternal(buffer, len, true);
130   }
131
132   // Same as read, but w/ strings - this tends to be slower..
133   // If len == -1 read to the end of input, else read len bytes.
134   // Returns anyway the number of read bytes
135   int32 ReadString(string* s, int32 len = -1);
136
137
138   // These are really slow - do not use them unless for debugging..
139   string ToString() {
140     string s;
141     ReadString(&s);
142     return s;
143   }
144   string DebugString() const {
145 #ifdef _DEBUG
146     string s;
147     MemoryStream* m = const_cast<MemoryStream*>(this);
148     m->MarkerSet();
149     m->ReadString(&s);
150     m->MarkerRestore();
151     return s;
152 #else
153     return "!!! io::MemoryStream::DebugString in Release Mode !!!";
154 #endif
155   }
156
157   // Utility to read from the pointer to a CRLF. Will leave the pointer
158   // after the CRLF or at the end of the buffer. Returns true (and reads)
159   // a line if found. On true, s will contain the line *and* the CRLF
160   bool ReadCRLFLine(string* s) {
161     if ( !MaybeInitReadPointer() ) {
162       return false;
163     }
164     if ( read_pointer_.ReadCRLFLine(s) ) {
165       size_ -= s->size();
166       return true;
167     }
168     return false;
169   }
170
171   // Same as above, but looks only for \n
172   bool ReadLFLine(string* s) {
173     if ( !MaybeInitReadPointer() ) {
174       return false;
175     }
176     if ( read_pointer_.ReadLFLine(s) ) {
177       size_ -= s->size();
178       return true;
179     }
180     return false;
181   }
182
183   // Read the next token - which can be:
184   //  - a separator char by itself
185   //  - a succession of non blank, non separator charactes
186   //  - a full string beginning w/ ' or "
187   //    - treats " and ' as begin of string / end of string
188   //  - passes over blanks
189   TokenReadError ReadNextAsciiToken(string* s) {
190     if ( !MaybeInitReadPointer() ) {
191       return TOKEN_NO_DATA;
192     }
193     int len;
194     TokenReadError ret =  read_pointer_.ReadNextAsciiToken(s, &len);
195     size_ -= len;
196     return ret;
197   }
198
199   // Not acutlly reading len bytes into buffer :)
200   int32 Peek(void* buffer, int32 len) const {
201     MemoryStream& This = const_cast<MemoryStream&>(*this);
202     const DataBlockPointer saved(This.read_pointer_);
203     const int32 saved_size = This.size_;
204     const int32 cb = This.ReadInternal(buffer, len, false);
205     This.read_pointer_ = saved;
206     This.size_ = saved_size;
207     return cb;
208   }
209
210   // Passes over "len" bytes. (Advances the read head by the "len" number of
211   // bytes). Returns the number of bytes skipped. Can be less than "len"
212   // if less bytes are available.
213   int32 Skip(int32 len);
214
215   // Clears the buffer
216   void Clear();
217
218   // Append "len" bytes of data from the given "buffer" to the stream
219   // Returns the number of bytes written. Can be less than len if the stream
220   // has not enough space, or negative on error.
221   int32 Write(const void* buffer, int32 len);
222
223   // Convenience function for writing a NULL terminated string.
224   int32 Write(const char* text) {
225     return Write(text, strlen(text));
226   }
227   // Convenience function for writing a string
228   int32 Write(const string& s) {
229     return Write(s.data(), s.size());
230   }
231
232   //////////////////////////////////////////////////////////////////////
233   //
234   // MARKER interface (reasonaby fast, w/ exception of Restore()
235   //
236
237   // Sets the marker in the current stream possition
238   void MarkerSet() {
239     if ( markers_.empty() ) {
240       invalid_markers_size_ = false;
241     }
242     markers_.push_back(make_pair(size_, new DataBlockPointer(read_pointer_)));
243   }
244   // Returns true iff the some marker is set
245   bool MarkerIsSet() const {
246     return !markers_.empty();
247   }
248   // Restores the position of the associated stream to the position
249   // previously marked by set.
250   void MarkerRestore() {
251     DCHECK(!markers_.empty());
252     read_pointer_ = *markers_.back().second;
253     if ( invalid_markers_size_ ) {
254       // unfortunately no smarter way for doing this, so we basically invalidate
255       // it..
256       if ( !MaybeInitReadPointer() ) {
257         size_ = 0;
258       } else {
259         size_ = read_pointer_.Distance(write_pointer_);
260       }
261       size_ = read_pointer_.Distance(write_pointer_);
262     } else {
263       size_ = markers_.back().first;
264     }
265     delete markers_.back().second;
266     markers_.pop_back();
267   }
268   // Removes the last mark for the underlying stream
269   void MarkerClear() {
270     delete markers_.back().second;
271     markers_.pop_back();
272   }
273
274   //////////////////////////////////////////////////////////////////////
275   //
276   // DEBUG functions (terribly slow)
277
278   // Utility debug function
279   string DumpContent(int32 max_size = -1) const;
280   string DumpContentHex(int32 max_size = -1) const;
281
282   string DetailedContent() const;
283
284  protected:
285   // Does the actual reading
286   int32 ReadInternal(void* buffer, int32 len, bool dispose);
287
288   bool MaybeInitReadPointer() const {
289     if ( read_pointer_.IsNull() ) {
290       if ( write_pointer_.IsNull() )
291         return false;
292       CHECK(read_pointer_.owner() != NULL);
293       (const_cast<DataBlockPointer*>(&read_pointer_))->set_block_id(
294         blocks_.begin_id());
295     }
296     return true;
297   }
298
299   // when the pointer advances, we may dispose some of the underlying blocks
300   void MaybeDisposeBlocks();
301
302
303   // We allocate buffer of this size by default
304   const BlockSize block_size_;
305   // Normally ints are written / read from here
306   common::ByteOrder byte_order_;
307
308   BlockDqueue blocks_;
309   DataBlockPointer read_pointer_;
310   DataBlockPointer write_pointer_;
311   DataBlockPointer scratch_pointer_;
312
313   // These are for marking positions in the stream
314   typedef vector < pair<int, DataBlockPointer*> > MarkersList;
315   MarkersList markers_;
316   bool invalid_markers_size_;
317   // We keep track of our internal size *all* the time - this is of
318   // utmost importance in maintaining a fast response.
319   // (At all times size_ == read_pointer_.Distance(write_pointer_);
320   int32 size_;
321
322  private:
323   DISALLOW_EVIL_CONSTRUCTORS(MemoryStream);
324 };
325
326 typedef BaseNumStreamer<MemoryStream, MemoryStream> NumStreamer;
327 }
328 #endif  // __COMMON_IO_BUFFER_MEMORY_STREAM_H__
Note: See TracBrowser for help on using the browser.