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

Generated on Fri Nov 11 18:44:24 2005 for Mango by  doxygen 1.4.0