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