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

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

Generated on Sat Apr 9 20:11:24 2005 for Mango by doxygen 1.3.6