1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2004 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Mar 2004: Initial release$(BR)
8                         Dec 2006: Outback release
9 
10         authors:        Kris
11 
12 *******************************************************************************/
13 
14 module tango.io.stream.Buffered;
15 
16 public import tango.io.model.IConduit;
17 
18 private import tango.io.device.Conduit;
19 
20 /******************************************************************************
21 
22 ******************************************************************************/
23 
24 public alias BufferedInput  Bin;        /// Shorthand aliases.
25 public alias BufferedOutput Bout;       /// ditto
26 
27 /******************************************************************************
28 
29 ******************************************************************************/
30 
31 extern (C)
32 {
33         int printf (char*, ...);
34         private void * memmove (void *dst, const(void) *src, size_t);
35 }
36 
37 /******************************************************************************
38 
39 ******************************************************************************/
40 
41 private __gshared immutable immutable(char)[] underflow = "input buffer is empty";
42 private __gshared immutable immutable(char)[] eofRead   = "end-of-flow whilst reading";
43 private __gshared immutable immutable(char)[] eofWrite  = "end-of-flow whilst writing";
44 private __gshared immutable immutable(char)[] overflow  = "output buffer is full";
45 
46 
47 /*******************************************************************************
48 
49         Buffers the flow of data from a upstream input. A downstream
50         neighbour can locate and use this buffer instead of creating
51         another instance of their own.
52 
53         (Note that upstream is closer to the source, and downstream is
54         further away.)
55 
56 *******************************************************************************/
57 
58 class BufferedInput : InputFilter, InputBuffer
59 {
60         alias flush             clear;          /// Clear/flush are the same.
61         alias InputFilter.input input;          /// Access the source.
62 
63         private void[]        data;             // The raw data buffer.
64         private size_t        index;            // Current read position.
65         private size_t        extent;           // Limit of valid content.
66         private size_t        dimension;        // Maximum extent of content.
67 
68         /***********************************************************************
69 
70                 Ensure the buffer remains valid between method calls.
71 
72         ***********************************************************************/
73 
74         invariant()
75         {
76                 assert (index <= extent);
77                 assert (extent <= dimension);
78         }
79 
80         /***********************************************************************
81 
82                 Construct a buffer.
83 
84                 Params:
85                 stream = An input stream.
86                 capacity = Desired buffer capacity.
87 
88                 Remarks:
89                 Construct a Buffer upon the provided input stream.
90 
91         ***********************************************************************/
92 
93         this (InputStream stream)
94         {
95                 assert (stream);
96                 this (stream, stream.conduit.bufferSize);
97         }
98 
99         /***********************************************************************
100 
101                 Construct a buffer.
102 
103                 Params:
104                 stream = An input stream.
105                 capacity = Desired buffer capacity.
106 
107                 Remarks:
108                 Construct a Buffer upon the provided input stream.
109 
110         ***********************************************************************/
111 
112         this (InputStream stream, size_t capacity)
113         {
114                 set (new ubyte[capacity], 0);
115                 super (source = stream);
116         }
117 
118         /***********************************************************************
119 
120                 Attempt to share an upstream Buffer, and create an instance
121                 where there's not one available.
122 
123                 Params:
124                 stream = An input stream.
125 
126                 Remarks:
127                 If an upstream Buffer instances is visible, it will be shared.
128                 Otherwise, a new instance is created based upon the bufferSize
129                 exposed by the stream endpoint (conduit).
130 
131         ***********************************************************************/
132 
133         static InputBuffer create (InputStream stream)
134         {
135                 auto source = stream;
136                 auto conduit = source.conduit;
137                 while (cast(Mutator) source is null)
138                       {
139                       auto b = cast(InputBuffer) source;
140                       if (b)
141                           return b;
142                       if (source is conduit)
143                           break;
144                       source = source.input;
145                       assert (source);
146                       }
147 
148                 return new BufferedInput (stream, conduit.bufferSize);
149         }
150 
151         /***********************************************************************
152 
153                 Place more data from the source stream into this buffer, and
154                 return the number of bytes added. This does not compress the
155                 current buffer content, so consider doing that explicitly.
156 
157                 Returns: Number of bytes added, which will be Eof when there
158                          is no further input available. Zero is also a valid
159                          response, meaning no data was actually added.
160 
161         ***********************************************************************/
162 
163         final size_t populate ()
164         {
165                 return writer (&input.read);
166         }
167 
168         /***********************************************************************
169 
170                 Return a void[] slice of the buffer from start to end, where
171                 end is exclusive.
172 
173         ***********************************************************************/
174 
175         final void[] opSlice (size_t start, size_t end)
176         {
177                 assert (start <= extent && end <= extent && start <= end);
178                 return data [start .. end];
179         }
180 
181         /***********************************************************************
182 
183                 Retrieve the valid content.
184 
185                 Returns:
186                 A void[] slice of the buffer.
187 
188                 Remarks:
189                 Return a void[] slice of the buffer, from the current position
190                 up to the limit of valid content. The content remains in the
191                 buffer for future extraction.
192 
193         ***********************************************************************/
194 
195         final void[] slice ()
196         {
197                 return  data [index .. extent];
198         }
199 
200         /***********************************************************************
201 
202                 Access buffer content.
203 
204                 Params:
205                 size =  Number of bytes to access.
206                 eat =   Whether to consume the content or not.
207 
208                 Returns:
209                 The corresponding buffer slice when successful, or
210                 null if there's not enough data available (Eof; Eob).
211 
212                 Remarks:
213                 Read a slice of data from the buffer, loading from the
214                 conduit as necessary. The specified number of bytes is
215                 sliced from the buffer, and marked as having been read
216                 when the 'eat' parameter is set true. When 'eat' is set
217                 false, the read position is not adjusted.
218 
219                 Note that the slice cannot be larger than the size of
220                 the buffer ~ use method fill(void[]) instead where you
221                 simply want the content copied, or use conduit.read()
222                 to extract directly from an attached conduit. Also note
223                 that if you need to retain the slice, then it should be
224                 .dup'd before the buffer is compressed or repopulated.
225 
226                 Examples:
227                 ---
228                 // create a buffer with some content
229                 auto buffer = new Buffer ("hello world");
230 
231                 // consume everything unread
232                 auto slice = buffer.slice (buffer.readable);
233                 ---
234 
235         ***********************************************************************/
236 
237         final void[] slice (size_t size, bool eat = true)
238         {
239                 if (size > readable)
240                    {
241                    // make some space? This will try to leave as much content
242                    // in the buffer as possible, such that entire records may
243                    // be aliased directly from within.
244                    if (size > (dimension - index))
245                    {
246                        if (size <= dimension)
247                            compress;
248                        else
249                           conduit.error (underflow);
250                    }
251                    // populate tail of buffer with new content
252                    do {
253                       if (writer (&source.read) is Eof)
254                           conduit.error (eofRead);
255                       } while (size > readable);
256                    }
257 
258                 auto i = index;
259                 if (eat)
260                     index += size;
261                 return data [i .. i + size];
262         }
263 
264         /***********************************************************************
265 
266                 Read directly from this buffer.
267 
268                 Params:
269                 dg = Callback to provide buffer access to.
270 
271                 Returns:
272                 Returns whatever the delegate returns.
273 
274                 Remarks:
275                 Exposes the raw data buffer at the current _read position. The
276                 delegate is provided with a void[] representing the available
277                 data, and should return zero to leave the current _read position
278                 intact.
279 
280                 If the delegate consumes data, it should return the number of
281                 bytes consumed; or IConduit.Eof to indicate an error.
282 
283         ***********************************************************************/
284 
285         final size_t reader (scope size_t delegate (const(void)[]) dg)
286         {
287                 auto count = dg (data [index..extent]);
288 
289                 if (count != Eof)
290                    {
291                    index += count;
292                    assert (index <= extent);
293                    }
294                 return count;
295         }
296 
297         /***********************************************************************
298 
299                 Write into this buffer.
300 
301                 Params:
302                 dg = The callback to provide buffer access to.
303 
304                 Returns:
305                 Returns whatever the delegate returns.
306 
307                 Remarks:
308                 Exposes the raw data buffer at the current _write position,
309                 The delegate is provided with a void[] representing space
310                 available within the buffer at the current _write position.
311 
312                 The delegate should return the appropriate number of bytes
313                 if it writes valid content, or IConduit.Eof on error.
314 
315         ***********************************************************************/
316 
317         public size_t writer (scope size_t delegate (void[]) dg)
318         {
319                 auto count = dg (data [extent..dimension]);
320 
321                 if (count != Eof)
322                    {
323                    extent += count;
324                    assert (extent <= dimension);
325                    }
326                 return count;
327         }
328 
329         /***********************************************************************
330 
331                 Transfer content into the provided dst.
332 
333                 Params:
334                 dst = Destination of the content.
335 
336                 Returns:
337                 Return the number of bytes read, which may be less than
338                 dst.length. Eof is returned when no further content is
339                 available.
340 
341                 Remarks:
342                 Populates the provided array with content. We try to
343                 satisfy the request from the buffer content, and read
344                 directly from an attached conduit when the buffer is
345                 empty.
346 
347         ***********************************************************************/
348 
349         final override size_t read (void[] dst)
350         {
351                 size_t content = readable;
352                 if (content)
353                    {
354                    if (content >= dst.length)
355                        content = dst.length;
356 
357                    // transfer buffer content
358                    dst [0 .. content] = data [index .. index + content];
359                    index += content;
360                    }
361                 else
362                    // pathological cases read directly from conduit
363                    if (dst.length > dimension)
364                        content = source.read (dst);
365                    else
366                       {
367                       if (writable is 0)
368                           index = extent = 0;  // same as clear, without call-chain
369 
370                       // keep buffer partially populated
371                       if ((content = writer (&source.read)) != Eof && content > 0)
372                            content = read (dst);
373                       }
374                 return content;
375         }
376 
377         /**********************************************************************
378 
379                 Fill the provided buffer. Returns the number of bytes
380                 actually read, which will be less that dst.length when
381                 Eof has been reached and Eof thereafter.
382 
383                 Params:
384                 dst = Where data should be placed.
385                 exact = Whether to throw an exception when dst is not
386                         filled (an Eof occurs first). Defaults to false.
387 
388         **********************************************************************/
389 
390         final size_t fill (void[] dst, bool exact = false)
391         {
392                 size_t len = 0;
393 
394                 while (len < dst.length)
395                       {
396                       size_t i = read (dst [len .. $]);
397                       if (i is Eof)
398                          {
399                          if (exact && len < dst.length)
400                              conduit.error (eofRead);
401                          return (len > 0) ? len : Eof;
402                          }
403                       len += i;
404                       }
405                 return len;
406         }
407 
408         /***********************************************************************
409 
410                 Move the current read location.
411 
412                 Params:
413                 size = The number of bytes to move.
414 
415                 Returns:
416                 Returns true if successful, false otherwise.
417 
418                 Remarks:
419                 Skip ahead by the specified number of bytes, streaming from
420                 the associated conduit as necessary.
421 
422                 Can also reverse the read position by 'size' bytes, when size
423                 is negative. This may be used to support lookahead operations.
424                 Note that a negative size will fail where there is not sufficient
425                 content available in the buffer (can't _skip beyond the beginning).
426 
427         ***********************************************************************/
428 
429         final bool skip (ptrdiff_t size)
430         {
431                 if (size < 0)
432                    {
433                    size = -size;
434                    if (index >= size)
435                       {
436                       index -= size;
437                       return true;
438                       }
439                    return false;
440                    }
441                 return slice(size) !is null;
442         }
443 
444         /***********************************************************************
445 
446                 Move the current read location.
447 
448         ***********************************************************************/
449 
450         final override long seek (long offset, Anchor start = Anchor.Begin)
451         {
452                 if (start is Anchor.Current)
453                    {
454                    // handle this specially because we know this is
455                    // buffered - we should take into account the buffer
456                    // position when seeking
457                    offset -= readable;
458                    auto bpos = offset + limit;
459 
460                    if (bpos >= 0 && bpos < limit)
461                       {
462                       // the new position is within the current
463                       // buffer, skip to that position.
464                       skip (cast(int) bpos - cast(int) position);
465 
466                       // see if we can return a valid offset
467                       auto pos = source.seek (0, Anchor.Current);
468                       if (pos != Eof)
469                           return pos - readable;
470                       return Eof;
471                       }
472                    // else, position is outside the buffer. Do a real
473                    // seek using the adjusted position.
474                    }
475 
476                 clear();
477                 return source.seek (offset, start);
478         }
479 
480         /***********************************************************************
481 
482                 Iterator support.
483 
484                 Params:
485                 scan = The delegate to invoke with the current content.
486 
487                 Returns:
488                 Returns true if a token was isolated, false otherwise.
489 
490                 Remarks:
491                 Upon success, the delegate should return the byte-based
492                 index of the consumed pattern (tail end of it). Failure
493                 to match a pattern should be indicated by returning an
494                 Eof
495 
496                 Each pattern is expected to be stripped of the delimiter.
497                 An end-of-file condition causes trailing content to be
498                 placed into the token. Requests made beyond Eof result
499                 in empty matches (length is zero).
500 
501                 Note that additional iterator and/or reader instances
502                 will operate in lockstep when bound to a common buffer.
503 
504         ***********************************************************************/
505 
506         final bool next (scope size_t delegate (const(void)[]) scan)
507         {
508                 while (reader(scan) is Eof)
509                       {
510                       // did we start at the beginning?
511                       if (position)
512                           // yep - move partial token to start of buffer
513                           compress;
514                       else
515                          // no more space in the buffer?
516                          if (writable is 0)
517                              conduit.error ("BufferedInput.next :: input buffer is full");
518 
519                       // read another chunk of data
520                       if (writer(&source.read) is Eof)
521                           return false;
522                       }
523                 return true;
524         }
525 
526         /***********************************************************************
527 
528                 Reserve the specified space within the buffer, compressing
529                 existing content as necessary to make room.
530 
531                 Returns the current read point, after compression if that
532                 was required.
533 
534         ***********************************************************************/
535 
536         final size_t reserve (size_t space)
537         {
538                 assert (space < dimension);
539 
540                 if ((dimension - index) < space)
541                      compress;
542                 return index;
543         }
544 
545         /***********************************************************************
546 
547                 Compress buffer space.
548 
549                 Returns:
550                 The buffer instance.
551 
552                 Remarks:
553                 If we have some data left after an export, move it to
554                 front-of-buffer and set position to be just after the
555                 remains. This is for supporting certain conduits which
556                 choose to write just the initial portion of a request.
557 
558                 Limit is set to the amount of data remaining. Position
559                 is always reset to zero.
560 
561         ***********************************************************************/
562 
563         @property final BufferedInput compress ()
564         {
565                 auto r = readable;
566 
567                 if (index > 0 && r > 0)
568                     // content may overlap ...
569                     memmove (&data[0], &data[index], r);
570 
571                 index = 0;
572                 extent = r;
573                 return this;
574         }
575 
576         /***********************************************************************
577 
578                 Drain buffer content to the specific conduit.
579 
580                 Returns:
581                 Returns the number of bytes written, or Eof.
582 
583                 Remarks:
584                 Write as much of the buffer that the associated conduit
585                 can consume. The conduit is not obliged to consume all
586                 content, so some may remain within the buffer.
587 
588         ***********************************************************************/
589 
590         final size_t drain (OutputStream dst)
591         {
592                 assert (dst);
593 
594                 size_t ret = reader (&dst.write);
595                 compress;
596                 return ret;
597         }
598 
599         /***********************************************************************
600 
601                 Access buffer limit.
602 
603                 Returns:
604                 Returns the limit of readable content within this buffer.
605 
606                 Remarks:
607                 Each buffer has a capacity, a limit, and a position. The
608                 capacity is the maximum content a buffer can contain, limit
609                 represents the extent of valid content, and position marks
610                 the current read location.
611 
612         ***********************************************************************/
613 
614         @property final const size_t limit ()
615         {
616                 return extent;
617         }
618 
619         /***********************************************************************
620 
621                 Access buffer capacity.
622 
623                 Returns:
624                 Returns the maximum capacity of this buffer.
625 
626                 Remarks:
627                 Each buffer has a capacity, a limit, and a position. The
628                 capacity is the maximum content a buffer can contain, limit
629                 represents the extent of valid content, and position marks
630                 the current read location.
631 
632         ***********************************************************************/
633 
634         final const size_t capacity ()
635         {
636                 return dimension;
637         }
638 
639         /***********************************************************************
640 
641                 Access buffer read position.
642 
643                 Returns:
644                 Returns the current read-position within this buffer.
645 
646                 Remarks:
647                 Each buffer has a capacity, a limit, and a position. The
648                 capacity is the maximum content a buffer can contain, limit
649                 represents the extent of valid content, and position marks
650                 the current read location.
651 
652         ***********************************************************************/
653 
654         @property final const size_t position ()
655         {
656                 return index;
657         }
658 
659         /***********************************************************************
660 
661                 Available content.
662 
663                 Remarks:
664                 Return count of _readable bytes remaining in buffer. This is
665                 calculated simply as limit() - position().
666 
667         ***********************************************************************/
668 
669         @property final const size_t readable ()
670         {
671                 return extent - index;
672         }
673 
674         /***********************************************************************
675 
676                 Cast to a target type without invoking the wrath of the
677                 runtime checks for misalignment. Instead, we truncate the
678                 array length.
679 
680         ***********************************************************************/
681 
682         static inout(T)[] convert(T)(inout(void)[] x)
683         {
684                 return (cast(inout(T)*) x.ptr) [0 .. (x.length / T.sizeof)];
685         }
686 
687         /***********************************************************************
688 
689                 Clear buffer content.
690 
691                 Remarks:
692                 Reset 'position' and 'limit' to zero. This effectively
693                 clears all content from the buffer.
694 
695         ***********************************************************************/
696 
697         final override BufferedInput flush ()
698         {
699                 index = extent = 0;
700 
701                 // clear the filter chain also
702                 if (source)
703                     super.flush();
704                 return this;
705         }
706 
707         /***********************************************************************
708 
709                 Set the input stream.
710 
711         ***********************************************************************/
712 
713         @property final void input (InputStream source)
714         {
715                 this.source = source;
716         }
717 
718         /***********************************************************************
719 
720                 Load the bits from a stream, up to an indicated length, and
721                 return them all in an array. The function may consume more
722                 than the indicated size where additional data is available
723                 during a block read operation, but will not wait for more
724                 than specified. An Eof terminates the operation.
725 
726                 Returns an array representing the content, and throws
727                 IOException on error.
728 
729         ***********************************************************************/
730 
731         final override void[] load (size_t max = size_t.max)
732         {
733                 load (super.input, super.conduit.bufferSize, max);
734                 return slice();
735         }
736 
737         /***********************************************************************
738 
739                 Import content from the specified conduit, expanding
740                 as necessary up to the indicated maximum or until an
741                 Eof occurs.
742 
743                 Returns the number of bytes contained.
744 
745         ***********************************************************************/
746 
747         private size_t load (InputStream src, size_t increment, size_t max)
748         {
749                 size_t  len,
750                         count;
751 
752                 // make some room
753                 compress;
754 
755                 // explicitly resize?
756                 if (max != max.max)
757                     if ((len = writable) < max)
758                          increment = max - len;
759 
760                 while (count < max)
761                       {
762                       if (! writable)
763                          {
764                          dimension += increment;
765                          data.length = dimension;
766                          }
767                       if ((len = writer(&src.read)) is Eof)
768                            break;
769                       else
770                          count += len;
771                       }
772                 return count;
773         }
774 
775         /***********************************************************************
776 
777                 Reset the buffer content.
778 
779                 Params:
780                 data =          The backing array to buffer within.
781                 readable =      The number of bytes within data considered
782                                 valid.
783 
784                 Returns:
785                 The buffer instance.
786 
787                 Remarks:
788                 Set the backing array with some content readable. Writing
789                 to this will either flush it to an associated conduit, or
790                 raise an Eof condition. Use clear() to reset the content
791                 (make it all writable).
792 
793         ***********************************************************************/
794 
795         private final BufferedInput set (void[] data, size_t readable)
796         {
797                 this.data = data;
798                 this.extent = readable;
799                 this.dimension = data.length;
800 
801                 // reset to start of input
802                 this.index = 0;
803 
804                 return this;
805         }
806 
807         /***********************************************************************
808 
809                 Available space.
810 
811                 Remarks:
812                 Return count of _writable bytes available in buffer. This is
813                 calculated simply as capacity() - limit().
814 
815         ***********************************************************************/
816 
817         @property private final const size_t writable ()
818         {
819                 return dimension - extent;
820         }
821 }
822 
823 
824 
825 /*******************************************************************************
826 
827         Buffers the flow of data from a upstream output. A downstream
828         neighbour can locate and use this buffer instead of creating
829         another instance of their own.
830 
831         (Note that upstream is closer to the source, and downstream is
832         further away.)
833 
834         Don't forget to flush() buffered content before closing.
835 
836 *******************************************************************************/
837 
838 class BufferedOutput : OutputFilter, OutputBuffer
839 {
840         alias OutputFilter.output output;       /// access the sink
841 
842         private void[]        data;             // the raw data buffer
843         private size_t        index;            // current read position
844         private size_t        extent;           // limit of valid content
845         private size_t        dimension;        // maximum extent of content
846 
847         /***********************************************************************
848 
849                 Ensure the buffer remains valid between method calls.
850 
851         ***********************************************************************/
852 
853         invariant()
854         {
855                 assert (index <= extent);
856                 assert (extent <= dimension);
857         }
858 
859         /***********************************************************************
860 
861                 Construct a buffer.
862 
863                 Params:
864                 stream = An input stream.
865                 capacity = Desired buffer capacity.
866 
867                 Remarks:
868                 Construct a Buffer upon the provided input stream.
869 
870         ***********************************************************************/
871 
872         this (OutputStream stream)
873         {
874                 assert (stream);
875                 this (stream, stream.conduit.bufferSize);
876         }
877 
878         /***********************************************************************
879 
880                 Construct a buffer.
881 
882                 Params:
883                 stream = An input stream.
884                 capacity = Desired buffer capacity.
885 
886                 Remarks:
887                 Construct a Buffer upon the provided input stream.
888 
889         ***********************************************************************/
890 
891         this (OutputStream stream, size_t capacity)
892         {
893                 set (new ubyte[capacity], 0);
894                 super (sink = stream);
895         }
896 
897         /***********************************************************************
898 
899                 Attempts to share an upstream BufferedOutput, and creates a new
900                 instance where there's not a shared one available.
901 
902                 Params:
903                 stream = An output stream.
904 
905                 Remarks:
906                 Where an upstream instance is visible it will be returned.
907                 Otherwise, a new instance is created based upon the bufferSize
908                 exposed by the associated conduit
909 
910         ***********************************************************************/
911 
912         static OutputBuffer create (OutputStream stream)
913         {
914                 auto sink = stream;
915                 auto conduit = sink.conduit;
916                 while (cast(Mutator) sink is null)
917                       {
918                       auto b = cast(OutputBuffer) sink;
919                       if (b)
920                           return b;
921                       if (sink is conduit)
922                           break;
923                       sink = sink.output;
924                       assert (sink);
925                       }
926 
927                 return new BufferedOutput (stream, conduit.bufferSize);
928         }
929 
930         /***********************************************************************
931 
932                 Retrieve the valid content.
933 
934                 Returns:
935                 A void[] slice of the buffer.
936 
937                 Remarks:
938                 Return a void[] slice of the buffer, from the current position
939                 up to the limit of valid content. The content remains in the
940                 buffer for future extraction.
941 
942         ***********************************************************************/
943 
944         final void[] slice ()
945         {
946                 return data [index .. extent];
947         }
948 
949         /***********************************************************************
950 
951                 Emulate OutputStream.write().
952 
953                 Params:
954                 src = The content to write.
955 
956                 Returns:
957                 Return the number of bytes written, which may be less than
958                 provided (conceptually).
959 
960                 Remarks:
961                 Appends src content to the buffer, flushing to an attached
962                 conduit as necessary. An IOException is thrown upon write
963                 failure.
964 
965         ***********************************************************************/
966 
967         final override size_t write (const(void)[] src)
968         {
969                 append (src.ptr, src.length);
970                 return src.length;
971         }
972 
973         /***********************************************************************
974 
975                 Append content.
976 
977                 Params:
978                 src = The content to _append.
979 
980                 Returns a chaining reference if all content was written.
981                 Throws an IOException indicating Eof or Eob if not.
982 
983                 Remarks:
984                 Append an array to this buffer, and flush to the
985                 conduit as necessary. This is often used in lieu of
986                 a Writer.
987 
988         ***********************************************************************/
989 
990         final BufferedOutput append (const(void)[] src)
991         {
992                 return append (src.ptr, src.length);
993         }
994 
995         /***********************************************************************
996 
997                 Append content.
998 
999                 Params:
1000                 src = The content to _append.
1001                 length = The number of bytes in src.
1002 
1003                 Returns a chaining reference if all content was written.
1004                 Throws an IOException indicating Eof or Eob if not.
1005 
1006                 Remarks:
1007                 Append an array to this buffer, and flush to the
1008                 conduit as necessary. This is often used in lieu of
1009                 a Writer.
1010 
1011         ***********************************************************************/
1012 
1013         final BufferedOutput append (const(void)* src, size_t length)
1014         {
1015                 if (length > writable)
1016                    {
1017                    flush();
1018 
1019                    // check for pathological case
1020                    if (length > dimension)
1021                        do {
1022                           auto written = sink.write (src [0 .. length]);
1023                           if (written is Eof)
1024                               conduit.error (eofWrite);
1025                           length -= written;
1026                           src += written;
1027                           } while (length > dimension);
1028                     }
1029 
1030                 // avoid "out of bounds" test on zero length
1031                 if (length)
1032                    {
1033                    // content may overlap ...
1034                    memmove (&data[extent], src, length);
1035                    extent += length;
1036                    }
1037                 return this;
1038         }
1039 
1040         /***********************************************************************
1041 
1042                 Available space.
1043 
1044                 Remarks:
1045                 Return count of _writable bytes available in buffer. This is
1046                 calculated as capacity() - limit().
1047 
1048         ***********************************************************************/
1049 
1050         @property final const size_t writable ()
1051         {
1052                 return dimension - extent;
1053         }
1054 
1055         /***********************************************************************
1056 
1057                 Access buffer limit.
1058 
1059                 Returns:
1060                 Returns the limit of readable content within this buffer.
1061 
1062                 Remarks:
1063                 Each buffer has a capacity, a limit, and a position. The
1064                 capacity is the maximum content a buffer can contain, limit
1065                 represents the extent of valid content, and position marks
1066                 the current read location.
1067 
1068         ***********************************************************************/
1069 
1070         @property final const size_t limit ()
1071         {
1072                 return extent;
1073         }
1074 
1075         /***********************************************************************
1076 
1077                 Access buffer capacity.
1078 
1079                 Returns:
1080                 Returns the maximum capacity of this buffer.
1081 
1082                 Remarks:
1083                 Each buffer has a capacity, a limit, and a position. The
1084                 capacity is the maximum content a buffer can contain, limit
1085                 represents the extent of valid content, and position marks
1086                 the current read location.
1087 
1088         ***********************************************************************/
1089 
1090         final const size_t capacity ()
1091         {
1092                 return dimension;
1093         }
1094 
1095         /***********************************************************************
1096 
1097                 Truncate buffer content.
1098 
1099                 Remarks:
1100                 Truncate the buffer within its extent. Returns true if
1101                 the new length is valid, false otherwise.
1102 
1103         ***********************************************************************/
1104 
1105         final bool truncate (size_t length)
1106         {
1107                 if (length <= data.length)
1108                    {
1109                    extent = length;
1110                    return true;
1111                    }
1112                 return false;
1113         }
1114 
1115         /***********************************************************************
1116 
1117                 Cast to a target type without invoking the wrath of the
1118                 runtime checks for misalignment. Instead, we truncate the
1119                 array length.
1120 
1121         ***********************************************************************/
1122 
1123         static T[] convert(T)(void[] x)
1124         {
1125                 return (cast(T*) x.ptr) [0 .. (x.length / T.sizeof)];
1126         }
1127 
1128         /***********************************************************************
1129 
1130                 Flush all buffer content to the specific conduit.
1131 
1132                 Remarks:
1133                 Flush the contents of this buffer. This will block until
1134                 all content is actually flushed via the associated conduit,
1135                 whereas drain() will not.
1136 
1137                 Throws an IOException on premature Eof.
1138 
1139         ***********************************************************************/
1140 
1141         final override BufferedOutput flush ()
1142         {
1143                 while (readable > 0)
1144                       {
1145                       auto ret = reader (&sink.write);
1146                       if (ret is Eof)
1147                           conduit.error (eofWrite);
1148                       }
1149 
1150                 // flush the filter chain also
1151                 clear();
1152                 super.flush();
1153                 return this;
1154         }
1155 
1156         /***********************************************************************
1157 
1158                 Copy content via this buffer from the provided src
1159                 conduit.
1160 
1161                 Remarks:
1162                 The src conduit has its content transferred through
1163                 this buffer via a series of fill & drain operations,
1164                 until there is no more content available. The buffer
1165                 content should be explicitly flushed by the caller.
1166 
1167                 Throws an IOException on premature Eof.
1168 
1169         ***********************************************************************/
1170 
1171         final override BufferedOutput copy (InputStream src, size_t max = -1)
1172         {
1173                 size_t chunk,
1174                        copied;
1175 
1176                 while (copied < max && (chunk = writer(&src.read)) != Eof)
1177                       {
1178                       copied += chunk;
1179 
1180                       // don't drain until we actually need to
1181                       if (writable is 0)
1182                           if (drain(sink) is Eof)
1183                               conduit.error (eofWrite);
1184                       }
1185                 return this;
1186         }
1187 
1188         /***********************************************************************
1189 
1190                 Drain buffer content to the specific conduit.
1191 
1192                 Returns:
1193                 Returns the number of bytes written, or Eof.
1194 
1195                 Remarks:
1196                 Write as much of the buffer that the associated conduit
1197                 can consume. The conduit is not obliged to consume all
1198                 content, so some may remain within the buffer.
1199 
1200         ***********************************************************************/
1201 
1202         final size_t drain (OutputStream dst)
1203         {
1204                 assert (dst);
1205 
1206                 size_t ret = reader (&dst.write);
1207                 compress;
1208                 return ret;
1209         }
1210 
1211         /***********************************************************************
1212 
1213                 Clear buffer content.
1214 
1215                 Remarks:
1216                 Reset 'position' and 'limit' to zero. This effectively
1217                 clears all content from the buffer.
1218 
1219         ***********************************************************************/
1220 
1221         final BufferedOutput clear ()
1222         {
1223                 index = extent = 0;
1224                 return this;
1225         }
1226 
1227         /***********************************************************************
1228 
1229                 Set the output stream.
1230 
1231         ***********************************************************************/
1232 
1233         @property final void output (OutputStream sink)
1234         {
1235                 this.sink = sink;
1236         }
1237 
1238         /***********************************************************************
1239 
1240                 Seek within this stream. Any and all buffered output is
1241                 disposed before the upstream is invoked. Use an explicit
1242                 flush() to emit content prior to seeking.
1243 
1244         ***********************************************************************/
1245 
1246         final override long seek (long offset, Anchor start = Anchor.Begin)
1247         {
1248                 clear();
1249                 return super.seek (offset, start);
1250         }
1251 
1252         /***********************************************************************
1253 
1254                 Write into this buffer.
1255 
1256                 Params:
1257                 dg = The callback to provide buffer access to.
1258 
1259                 Returns:
1260                 Returns whatever the delegate returns.
1261 
1262                 Remarks:
1263                 Exposes the raw data buffer at the current _write position,
1264                 The delegate is provided with a void[] representing space
1265                 available within the buffer at the current _write position.
1266 
1267                 The delegate should return the appropriate number of bytes
1268                 if it writes valid content, or Eof on error.
1269 
1270         ***********************************************************************/
1271 
1272         final size_t writer (scope size_t delegate (void[]) dg)
1273         {
1274                 auto count = dg (data [extent..dimension]);
1275 
1276                 if (count != Eof)
1277                    {
1278                    extent += count;
1279                    assert (extent <= dimension);
1280                    }
1281                 return count;
1282         }
1283 
1284         /***********************************************************************
1285 
1286                 Read directly from this buffer.
1287 
1288                 Params:
1289                 dg = Callback to provide buffer access to.
1290 
1291                 Returns:
1292                 Returns whatever the delegate returns.
1293 
1294                 Remarks:
1295                 Exposes the raw data buffer at the current _read position. The
1296                 delegate is provided with a void[] representing the available
1297                 data, and should return zero to leave the current _read position
1298                 intact.
1299 
1300                 If the delegate consumes data, it should return the number of
1301                 bytes consumed; or Eof to indicate an error.
1302 
1303         ***********************************************************************/
1304 
1305         private final size_t reader (scope size_t delegate (const(void)[]) dg)
1306         {
1307                 auto count = dg (data [index..extent]);
1308 
1309                 if (count != Eof)
1310                    {
1311                    index += count;
1312                    assert (index <= extent);
1313                    }
1314                 return count;
1315         }
1316 
1317         /***********************************************************************
1318 
1319                 Available content.
1320 
1321                 Remarks:
1322                 Return count of _readable bytes remaining in buffer. This is
1323                 calculated simply as limit() - position().
1324 
1325         ***********************************************************************/
1326 
1327         @property private final const size_t readable ()
1328         {
1329                 return extent - index;
1330         }
1331 
1332         /***********************************************************************
1333 
1334                 Reset the buffer content.
1335 
1336                 Params:
1337                 data =     The backing array to buffer within.
1338                 readable = The number of bytes within data considered
1339                            valid.
1340 
1341                 Returns:
1342                 The buffer instance.
1343 
1344                 Remarks:
1345                 Set the backing array with some content readable. Writing
1346                 to this will either flush it to an associated conduit, or
1347                 raise an Eof condition. Use clear() to reset the content
1348                 (make it all writable).
1349 
1350         ***********************************************************************/
1351 
1352         private final BufferedOutput set (void[] data, size_t readable)
1353         {
1354                 this.data = data;
1355                 this.extent = readable;
1356                 this.dimension = data.length;
1357 
1358                 // reset to start of input
1359                 this.index = 0;
1360 
1361                 return this;
1362         }
1363 
1364         /***********************************************************************
1365 
1366                 Compress buffer space.
1367 
1368                 Returns:
1369                 The buffer instance.
1370 
1371                 Remarks:
1372                 If we have some data left after an export, move it to
1373                 front-of-buffer and set position to be just after the
1374                 remains. This is for supporting certain conduits which
1375                 choose to write just the initial portion of a request.
1376 
1377                 Limit is set to the amount of data remaining. Position
1378                 is always reset to zero.
1379 
1380         ***********************************************************************/
1381 
1382         @property private final BufferedOutput compress ()
1383         {
1384                 size_t r = readable;
1385 
1386                 if (index > 0 && r > 0)
1387                     // content may overlap ...
1388                     memmove (&data[0], &data[index], r);
1389 
1390                 index = 0;
1391                 extent = r;
1392                 return this;
1393         }
1394 }
1395 
1396 
1397 
1398 /******************************************************************************
1399 
1400 ******************************************************************************/
1401 
1402 debug (Buffered)
1403 {
1404         void main()
1405         {
1406                 auto input = new BufferedInput (null);
1407                 auto output = new BufferedOutput (null);
1408         }
1409 }