Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

Writer.d

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003         @file AbstractWriter.d
00004         
00005 
00006         Copyright (c) 2004 Kris Bell
00007         
00008         This software is provided 'as-is', without any express or implied
00009         warranty. In no event will the authors be held liable for damages
00010         of any kind arising from the use of this software.
00011         
00012         Permission is hereby granted to anyone to use this software for any 
00013         purpose, including commercial applications, and to alter it and/or 
00014         redistribute it freely, subject to the following restrictions:
00015         
00016         1. The origin of this software must not be misrepresented; you must 
00017            not claim that you wrote the original software. If you use this 
00018            software in a product, an acknowledgment within documentation of 
00019            said product would be appreciated but is not required.
00020 
00021         2. Altered source versions must be plainly marked as such, and must 
00022            not be misrepresented as being the original software.
00023 
00024         3. This notice may not be removed or altered from any distribution
00025            of the source.
00026 
00027         4. Derivative works are permitted, but they must carry this notice
00028            in full and credit the original source.
00029 
00030 
00031                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00032 
00033 
00034         @version        Initial version, October 2004    
00035           
00036         @author         Kris 
00037 
00038 *******************************************************************************/
00039 
00040 module mango.io.Writer;
00041 
00042 private import  mango.convert.Type;
00043 
00044 private import  mango.io.Exception;
00045 
00046 public  import  mango.io.Buffer;
00047 
00048 public  import  mango.io.model.IWriter,
00049                 mango.io.model.IBuffer,
00050                 mango.io.model.IConduit;
00051 
00052 /*******************************************************************************
00053 
00054         Writer base-class. Writers provide the means to append formatted 
00055         data to an IBuffer, and expose a convenient method of handling a
00056         variety of data types. In addition to writing native types such
00057         as integer and char[], writers also process any class which has
00058         implemented the IWritable interface (one method).
00059 
00060         All writers support the full set of native data types, plus their
00061         fundamental array variants. Operations may be chained back-to-back.
00062 
00063         Writers support a C++ iostream type syntax, along with Java-esque 
00064         put() notation. However, the Mango style is to place IO elements 
00065         within their own parenthesis, like so:
00066         
00067                 write (count) (" green bottles");
00068 
00069         Note that each element is distict; this enables "strong typing", 
00070         which should catch any typo errors at compile-time. The style is
00071         affectionately called "whisper".
00072 
00073         The code below illustrates basic operation upon a memory buffer:
00074         
00075         @code
00076         Buffer buf = new Buffer (256);
00077 
00078         // map same buffer into both reader and writer
00079         IReader read = new Reader(buf);
00080         IWriter write = new Writer(buf);
00081 
00082         int i = 10;
00083         long j = 20;
00084         double d = 3.14159;
00085         char[] c = "fred";
00086 
00087         // write data types out
00088         write (c) (i) (j) (d);
00089 
00090         // read them back again
00091         read (c) (i) (j) (d);
00092 
00093         // reset
00094         buf.clear();
00095 
00096         // same thing again, but using iostream syntax instead
00097         write << c << i << j << d;
00098 
00099         // read them back again
00100         read >> c >> i >> j >> d;
00101 
00102         // reset
00103         buf.clear();
00104 
00105         // same thing again, but using put() syntax instead
00106         write.put(c).put(i).put(j).put(d);
00107         read.get(c).get(i).get(j).get(d);
00108 
00109         @endcode
00110 
00111         Writers may also be used with any class implementing the IWritable
00112         interface. See PickleReader for an example of how this can be put
00113         to good use.
00114 
00115         Note that 'newlines' are emitted via the standard "\n" approach. 
00116         However, one might consider using the public CR element instead.
00117 
00118         Writers also support formatted output via the DisplayWriter module,
00119         which has full support for printf() syntax:
00120 
00121         @code
00122         Stdout.println ("%d green bottles", 10);
00123         @endcode
00124         
00125         Lastly, each Writer may be configured with a text encoder. These
00126         encoders convert between an internal text representation, and the
00127         char/wchar/dchar representaion. BufferCodec.d contains classes for
00128         handling utf8, utf16, and utf32. The icu.UMango module has support
00129         for a wide variety of converters. Stdout is pre-configured with
00130         utf16 & utf8 encoders for Win32 and Posix respectively.
00131         
00132 *******************************************************************************/
00133 
00134 class Writer : IWriter
00135 {     
00136         protected IBuffer               buffer;
00137         private bool                    prefixArray;
00138         private IBuffer.Converter       textEncoder;
00139 
00140         /***********************************************************************
00141         
00142                 Construct a Writer upon the provided IBuffer. All formatted
00143                 output will be directed to this buffer.
00144 
00145         ***********************************************************************/
00146 
00147         this (IBuffer buffer)
00148         {
00149                 this.buffer = buffer;
00150                 
00151                 Buffer.Style s = buffer.getStyle;
00152                 if (s != Buffer.Mixed)
00153                     if ((s == Buffer.Text) ^ isTextBased())
00154                          error ("text/binary mismatch between Writer and Buffer");
00155                 prefixArray = cast(bool) !isTextBased;
00156         }
00157      
00158         /***********************************************************************
00159         
00160                 Construct a Writer on the buffer associated with the given
00161                 conduit.
00162 
00163         ***********************************************************************/
00164 
00165         this (IConduit conduit)
00166         {
00167                 this (new Buffer(conduit));
00168         }
00169 
00170         /***********************************************************************
00171         
00172         ***********************************************************************/
00173 
00174         final void error (char[] msg)
00175         {
00176                 buffer.error (msg);
00177         }
00178 
00179         /***********************************************************************
00180         
00181                 Return the associated buffer
00182 
00183         ***********************************************************************/
00184 
00185         final IBuffer getBuffer ()
00186         {     
00187                 return buffer;
00188         }
00189 
00190         /***********************************************************************
00191         
00192         ***********************************************************************/
00193 
00194         final IConduit conduit ()
00195         {
00196                 return buffer.getConduit();
00197         }
00198 
00199         /***********************************************************************
00200         
00201                 Bind an IEncoder to the writer. Encoders are intended to
00202                 be used as a conversion mechanism between various character
00203                 representations (encodings). Each writer may be configured 
00204                 with a distinct encoder.
00205 
00206         ***********************************************************************/
00207 
00208         final void setEncoder (AbstractEncoder e) 
00209         {
00210                 e.bind (buffer);
00211                 this.textEncoder = &e.encoder;
00212         }
00213 
00214         /***********************************************************************
00215         
00216                 Is this Writer text oriented?
00217 
00218         ***********************************************************************/
00219 
00220         bool isTextBased()
00221         {
00222                 return false;
00223         }
00224 
00225         /***********************************************************************
00226         
00227                 Flush the output of this writer. Returns false if the 
00228                 operation failed, true otherwise.
00229 
00230         ***********************************************************************/
00231 
00232         IWriter flush ()
00233         {  
00234                 buffer.flush ();
00235                 return this;
00236         }
00237 
00238         /***********************************************************************
00239         
00240                 Output a newline. Do this indirectly so that it can be 
00241                 intercepted by subclasses.
00242 
00243         ***********************************************************************/
00244 
00245         IWriter cr ()
00246         {
00247                 return put (CR);
00248         }
00249 
00250         /***********************************************************************
00251         
00252                 Flush this writer. This is a convenience method used by
00253                 the "whisper" syntax.
00254                 
00255         ***********************************************************************/
00256 
00257         IWriter put () 
00258         {
00259                 return flush ();
00260         }
00261 
00262         /***********************************************************************
00263         
00264                 Write a class to the current buffer-position
00265                 
00266         ***********************************************************************/
00267 
00268         IWriter put (IWritable x) 
00269         {
00270                 assert (x);
00271                 x.write (this); 
00272                 return this;
00273         }
00274 
00275         /***********************************************************************
00276         
00277                 Write a boolean value to the current buffer-position    
00278                 
00279         ***********************************************************************/
00280 
00281         IWriter put (bool x)
00282         {
00283                 return write (&x, x.sizeof, Type.Bool);
00284         }
00285 
00286         /***********************************************************************
00287         
00288                 Write an unsigned byte value to the current buffer-position     
00289                                 
00290         ***********************************************************************/
00291 
00292         IWriter put (ubyte x)
00293         {
00294                 return write (&x, x.sizeof, Type.UByte);
00295         }
00296 
00297         /***********************************************************************
00298         
00299                 Write a byte value to the current buffer-position
00300                 
00301         ***********************************************************************/
00302 
00303         IWriter put (byte x)
00304         {
00305                 return write (&x, x.sizeof, Type.Byte);
00306         }
00307 
00308         /***********************************************************************
00309         
00310                 Write an unsigned short value to the current buffer-position
00311                 
00312         ***********************************************************************/
00313 
00314         IWriter put (ushort x)
00315         {
00316                 return write (&x, x.sizeof, Type.UShort);
00317         }
00318 
00319         /***********************************************************************
00320         
00321                 Write a short value to the current buffer-position
00322                 
00323         ***********************************************************************/
00324 
00325         IWriter put (short x)
00326         {
00327                 return write (&x, x.sizeof, Type.Short);
00328         }
00329 
00330         /***********************************************************************
00331         
00332                 Write a unsigned int value to the current buffer-position
00333                 
00334         ***********************************************************************/
00335 
00336         IWriter put (uint x)
00337         {
00338                 return write (&x, x.sizeof, Type.UInt);
00339         }
00340 
00341         /***********************************************************************
00342         
00343                 Write an int value to the current buffer-position
00344                 
00345         ***********************************************************************/
00346 
00347         IWriter put (int x)
00348         {
00349                 return write (&x, x.sizeof, Type.Int);
00350         }
00351 
00352         /***********************************************************************
00353         
00354                 Write an unsigned long value to the current buffer-position
00355                 
00356         ***********************************************************************/
00357 
00358         IWriter put (ulong x)
00359         {
00360                 return write (&x, x.sizeof, Type.ULong);
00361         }
00362 
00363         /***********************************************************************
00364         
00365                 Write a long value to the current buffer-position
00366                 
00367         ***********************************************************************/
00368 
00369         IWriter put (long x)
00370         {
00371                 return write (&x, x.sizeof, Type.Long);
00372         }
00373 
00374         /***********************************************************************
00375         
00376                 Write a float value to the current buffer-position
00377                 
00378         ***********************************************************************/
00379 
00380         IWriter put (float x)
00381         {
00382                 return write (&x, x.sizeof, Type.Float);
00383         }
00384 
00385         /***********************************************************************
00386         
00387                 Write a double value to the current buffer-position
00388                 
00389         ***********************************************************************/
00390 
00391         IWriter put (double x)
00392         {
00393                 return write (&x, x.sizeof, Type.Double);
00394         }
00395 
00396         /***********************************************************************
00397         
00398                 Write a real value to the current buffer-position
00399                 
00400         ***********************************************************************/
00401 
00402         IWriter put (real x)
00403         {
00404                 return write (&x, x.sizeof, Type.Real);
00405         }
00406 
00407         /***********************************************************************
00408         
00409                 Write a char value to the current buffer-position
00410                 
00411         ***********************************************************************/
00412 
00413         IWriter put (char x)
00414         {
00415                 return encode (&x, char.sizeof, Type.Utf8);
00416         }
00417 
00418         /***********************************************************************
00419         
00420                 Write a wchar value to the current buffer-position
00421                 
00422         ***********************************************************************/
00423 
00424         IWriter put (wchar x)
00425         {
00426                 return encode (&x, wchar.sizeof, Type.Utf16);
00427         }
00428 
00429         /***********************************************************************
00430         
00431                 Write a dchar value to the current buffer-position
00432                 
00433         ***********************************************************************/
00434 
00435         IWriter put (dchar x)
00436         {
00437                 return encode (&x, dchar.sizeof, Type.Utf32);
00438         }
00439 
00440         /***********************************************************************
00441         
00442                 Write a byte array to the current buffer-position     
00443                                 
00444         ***********************************************************************/
00445 
00446         IWriter put (byte[] x)
00447         {
00448                 return write (x, length (x.length) * byte.sizeof, Type.Byte);
00449         }
00450 
00451         /***********************************************************************
00452         
00453                 Write an unsigned byte array to the current buffer-position     
00454                                 
00455         ***********************************************************************/
00456 
00457         IWriter put (ubyte[] x)
00458         {
00459                 return write (x, length (x.length) * ubyte.sizeof, Type.UByte);
00460         }
00461 
00462         /***********************************************************************
00463         
00464                 Write a short array to the current buffer-position
00465                 
00466         ***********************************************************************/
00467 
00468         IWriter put (short[] x)
00469         {
00470                 return write (x, length (x.length) * short.sizeof, Type.Short);
00471         }
00472 
00473         /***********************************************************************
00474         
00475                 Write an unsigned short array to the current buffer-position
00476                 
00477         ***********************************************************************/
00478 
00479         IWriter put (ushort[] x)
00480         {
00481                 return write (x, length (x.length) * ushort.sizeof, Type.UShort);
00482         }
00483 
00484         /***********************************************************************
00485         
00486                 Write an int array to the current buffer-position
00487                 
00488         ***********************************************************************/
00489 
00490         IWriter put (int[] x)
00491         {
00492                 return write (x, length (x.length) * int.sizeof, Type.Int);
00493         }
00494 
00495         /***********************************************************************
00496         
00497                 Write an unsigned int array to the current buffer-position
00498                 
00499         ***********************************************************************/
00500 
00501         IWriter put (uint[] x)
00502         {
00503                 return write (x, length (x.length) * uint.sizeof, Type.UInt);
00504         }
00505 
00506         /***********************************************************************
00507         
00508                 Write a long array to the current buffer-position
00509                 
00510         ***********************************************************************/
00511 
00512         IWriter put (long[] x)
00513         {
00514                 return write (x, length (x.length) * long.sizeof, Type.Long);
00515         }
00516 
00517         /***********************************************************************
00518         
00519                 Write an unsigned long array to the current buffer-position
00520                 
00521         ***********************************************************************/
00522 
00523         IWriter put (ulong[] x)
00524         {
00525                 return write (x, length (x.length) * ulong.sizeof, Type.ULong);
00526         }
00527 
00528         /***********************************************************************
00529         
00530                 Write a float array to the current buffer-position
00531                 
00532         ***********************************************************************/
00533 
00534         IWriter put (float[] x)
00535         {
00536                 return write (x, length (x.length) * float.sizeof, Type.Float);
00537         }
00538 
00539         /***********************************************************************
00540         
00541                 Write a double array to the current buffer-position
00542                 
00543         ***********************************************************************/
00544 
00545         IWriter put (double[] x)
00546         {
00547                 return write (x, length (x.length) * double.sizeof, Type.Double);
00548         }
00549 
00550         /***********************************************************************
00551         
00552                 Write a real array to the current buffer-position
00553                 
00554         ***********************************************************************/
00555 
00556         IWriter put (real[] x)
00557         {
00558                 return write (x, length (x.length) * real.sizeof, Type.Real);
00559         }
00560 
00561         /***********************************************************************
00562         
00563                 Write a char array to the current buffer-position
00564                 
00565         ***********************************************************************/
00566 
00567         IWriter put (char[] x) 
00568         {
00569                 return encode (x.ptr, length(x.length) * char.sizeof, Type.Utf8);
00570         }
00571 
00572         /***********************************************************************
00573         
00574                 Write a wchar array to the current buffer-position
00575                 
00576         ***********************************************************************/
00577 
00578         IWriter put (wchar[] x) 
00579         {
00580                 return encode (x.ptr, length(x.length) * wchar.sizeof, Type.Utf16);
00581         }
00582 
00583         /***********************************************************************
00584         
00585                 Write a dchar array to the current buffer-position
00586                 
00587         ***********************************************************************/
00588 
00589         IWriter put (dchar[] x)
00590         {
00591                 return encode (x.ptr, length(x.length) * dchar.sizeof, Type.Utf32);
00592         }
00593 
00594         /***********************************************************************
00595         
00596                 Dump content into the buffer. This is intercepted by a 
00597                 variety of subclasses 
00598 
00599         ***********************************************************************/
00600 
00601         protected IWriter write (void* src, uint bytes, int type)
00602         {
00603                 buffer.append (src [0 .. bytes]);
00604                 return this;
00605         }
00606 
00607         /***********************************************************************
00608         
00609                 Handle text output. This is intended to be intercepted
00610                 by subclasses, though they should always pump content
00611                 through here to take advantage of configured encoding
00612 
00613         ***********************************************************************/
00614 
00615         protected IWriter encode (void* src, uint bytes, int type)
00616         {
00617                 if (textEncoder)
00618                     textEncoder (src, bytes, type);
00619                 else
00620                    buffer.append (src [0 .. bytes]);
00621                 return this;
00622         }
00623 
00624         /***********************************************************************
00625         
00626                 Emit the length of an array: used for raw binary output
00627                 of arrays. Array lengths are written into the buffer as
00628                 a guide for when reading it back again
00629                 
00630         ***********************************************************************/
00631 
00632         private final uint length (uint len)
00633         {
00634                 if (prefixArray)
00635                     put (len);
00636                 return len;
00637         }
00638 }
00639 
00640 
00641 /*******************************************************************************
00642 
00643         A class to handle newline output. One might reasonably expect to 
00644         emit a char[] for newlines; FileConst.NewlineString for example.
00645         Turns out that it's much more efficient to intercept line-breaks
00646         when they're implemented in a more formal manner (such as this).
00647 
00648         For example, ColumnWriter() and TextWriter() both must intercept 
00649         newline output so they can adjust formatting appropriately. It is 
00650         much more efficient for such writers to intercept the IWritable 
00651         put() method instead of scanning each char[] for the various \\n 
00652         combinations.
00653         
00654         Please use the INewlineWriter interface for emitting newlines.
00655 
00656 *******************************************************************************/
00657 
00658 private import mango.io.FileConst;
00659 
00660 class NewlineWriter : INewlineWriter
00661 {
00662         private char[]  fmt;
00663 
00664         /***********************************************************************
00665 
00666                 Construct a default newline, using the char[] defined 
00667                 by FileConst.NewlineString
00668         
00669         ***********************************************************************/
00670 
00671         this ()
00672         {
00673                 this (FileConst.NewlineString);
00674         }
00675 
00676         /***********************************************************************
00677         
00678                 Construct a newline using the provided character array
00679 
00680         ***********************************************************************/
00681 
00682         this (char[] fmt)
00683         {
00684                 this.fmt = fmt;
00685         }
00686 
00687         /***********************************************************************
00688         
00689                 Write this newline through the provided writer. This makes
00690                 NewlineWriter IWritable compatible.
00691 
00692         ***********************************************************************/
00693 
00694         void write (IWriter w)
00695         {
00696                 w.put (fmt);
00697         }     
00698 }
00699 
00700 
00701 /*******************************************************************************
00702 
00703         public newline adaptor
00704 
00705 *******************************************************************************/
00706 
00707 public static NewlineWriter CR;
00708 
00709 static this ()
00710 {
00711         CR = new NewlineWriter;
00712 }
00713 

Generated on Sat Dec 24 17:28:34 2005 for Mango by  doxygen 1.4.0