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