00001 /******************************************************************************* 00002 00003 @file AbstractReader.d 00004 00005 Copyright (C) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 00027 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00028 00029 00030 @version Initial version, October 2004 00031 @author Kris 00032 00033 00034 *******************************************************************************/ 00035 00036 module mango.io.AbstractReader; 00037 00038 private import mango.io.Exception, 00039 mango.io.ArrayAllocator; 00040 00041 public import mango.io.model.IReader, 00042 mango.io.model.IBuffer, 00043 mango.io.model.IConduit; 00044 00045 00046 /******************************************************************************* 00047 00048 Reader base-class. Each reader operates upon an IBuffer, which is 00049 provided at construction time. Said buffer is intended to remain 00050 consistent over the reader lifetime. 00051 00052 Readers support both a C++ iostream type syntax, along with a get() 00053 syntax. Operations may be chained back-to-back. 00054 00055 All readers support the full set of integral 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 method 00058 setMapped() for more on this topic. 00059 00060 The code below illustrates basic operation upon a memory buffer: 00061 00062 @code 00063 Buffer buf = new Buffer (256); 00064 00065 // map same buffer into both reader and writer 00066 Reader r = new Reader(buf); 00067 Writer w = new Writer(buf); 00068 00069 int i = 10; 00070 long j = 20; 00071 double d = 3.14159; 00072 00073 // write data types out 00074 w << i << j << d; 00075 00076 // read them back again 00077 r >> i >> j >> d; 00078 00079 // reset 00080 buf.clear(); 00081 00082 // same thing again, but using get() syntax instead 00083 w.put(i).put(j).put(d); 00084 r.get(i).get(j).get(d); 00085 00086 @endcode 00087 00088 Readers may also be used with any class implementing the IReadable 00089 interface. See CompositeReader for an example of how this can be 00090 put to good use. 00091 00092 *******************************************************************************/ 00093 00094 class AbstractReader : SimpleAllocator, IReader 00095 { 00096 /*********************************************************************** 00097 00098 ***********************************************************************/ 00099 00100 struct NumericDecoder 00101 { 00102 BufferConverter int1, 00103 int8, 00104 int16, 00105 int32, 00106 int64, 00107 int8u, 00108 int16u, 00109 int32u, 00110 int64u, 00111 float32, 00112 float64, 00113 float80; 00114 } 00115 00116 /*********************************************************************** 00117 00118 ***********************************************************************/ 00119 00120 struct StringDecoder 00121 { 00122 BufferConverter char8, 00123 char16, 00124 char32; 00125 } 00126 00127 // a couple of pre-constructed exceptions 00128 private static EofException eof; 00129 private static IOException udf; 00130 00131 // the buffer associated with this reader. Note that this 00132 // must not change for the lifetime of the reader, since 00133 // it is assumed to be immutable elsewhere (subclass may 00134 // keep its own copy). 00135 protected IBuffer buffer; 00136 00137 // decoders for string requests 00138 protected StringDecoder string; 00139 00140 // decoders for numeric requests 00141 protected NumericDecoder numeric; 00142 00143 // memory-manager for array requests 00144 private IArrayAllocator memory; 00145 00146 // size for client-specified allocations 00147 private uint pushed = uint.max; 00148 00149 /*********************************************************************** 00150 00151 Return the name of this reader 00152 00153 ***********************************************************************/ 00154 00155 abstract char[] toString (); 00156 00157 /*********************************************************************** 00158 00159 Construct a couple of static exception instances. 00160 00161 ***********************************************************************/ 00162 00163 static this () 00164 { 00165 eof = new EofException ("premature end-of-input"); 00166 udf = new IOException ("input buffer underflow"); 00167 } 00168 00169 /*********************************************************************** 00170 00171 Return the buffer associated with this reader 00172 00173 ***********************************************************************/ 00174 00175 this (IBuffer buffer) 00176 { 00177 super (this); 00178 this.memory = this; 00179 this.buffer = buffer; 00180 } 00181 00182 /*********************************************************************** 00183 00184 Return the buffer associated with this reader 00185 00186 ***********************************************************************/ 00187 00188 final IBuffer getBuffer () 00189 { 00190 return buffer; 00191 } 00192 00193 /*********************************************************************** 00194 00195 Return the allocator associated with this reader.See 00196 ArrayAllocator for more information. 00197 00198 ***********************************************************************/ 00199 00200 final IArrayAllocator getAllocator () 00201 { 00202 return memory; 00203 } 00204 00205 /*********************************************************************** 00206 00207 Set the allocator to use for array management. Arrays are 00208 always allocated by the IReader. That is, you cannot read 00209 data into an array slice (for example). Instead, a number 00210 of IArrayAllocator classes are available to manage memory 00211 allocation when reading array content. 00212 00213 By default, an IReader will allocate each array from the 00214 heap. You can change that behavior by calling this method 00215 with an IArrayAllocator of choice. For instance, there 00216 is a BufferAllocator which will slice an array directly 00217 from the buffer where possible. Also available is the 00218 record-oriented SliceAllocator, which slices memory from 00219 within a pre-allocated heap area, and should be reset by 00220 the client code after each record has been read (to avoid 00221 unnecessary growth). 00222 00223 See ArrayAllocator for more information. 00224 00225 ***********************************************************************/ 00226 00227 final void setAllocator (IArrayAllocator memory) 00228 { 00229 if (! memory) 00230 memory = this; 00231 this.memory = memory; 00232 } 00233 00234 /*********************************************************************** 00235 00236 Set the configured IStringDecoder. These are intended to 00237 be used as a conversion mechanism between various character 00238 representations. They are also expected to be used for the 00239 process of applying character encodings. 00240 00241 See IStringDecoder. 00242 00243 ***********************************************************************/ 00244 00245 final void setStringDecoder (IStringDecoder s) 00246 { 00247 string.char8 = &s.char8; 00248 string.char16 = &s.char16; 00249 string.char32 = &s.char32; 00250 } 00251 00252 /*********************************************************************** 00253 00254 Push the size (in bytes) to use for the next array-read. 00255 By default, array sizes are read from the input stream, 00256 so this is the means by which one may specify the size 00257 where the stream is not formatted in such a manner. 00258 00259 @code 00260 char[] x; 00261 int size; 00262 IReader reader; 00263 00264 reader.push(size).get(x); 00265 @endcode 00266 00267 ***********************************************************************/ 00268 00269 final IReader push (uint size) 00270 { 00271 if (pushed == uint.max) 00272 pushed = size; 00273 else 00274 throw new IOException ("invalid IReader push-sequence"); 00275 return this; 00276 } 00277 00278 /*********************************************************************** 00279 00280 Read and return an integer from the input stream. This can 00281 be used to extract the length of a subsequent array. 00282 00283 ***********************************************************************/ 00284 00285 final uint length () 00286 { 00287 uint len = pushed; 00288 00289 if (len != uint.max) 00290 pushed = uint.max; 00291 else 00292 get (len); 00293 return len; 00294 } 00295 00296 /*********************************************************************** 00297 00298 Wait for something to arrive in the buffer. This may stall 00299 the current thread forever, although usage of SocketConduit 00300 will take advantage of the timeout facilities provided there. 00301 00302 ***********************************************************************/ 00303 00304 final void wait () 00305 { 00306 buffer.get (1, false); 00307 } 00308 00309 /*********************************************************************** 00310 00311 Extract a readable class from the current read-position 00312 00313 ***********************************************************************/ 00314 00315 final IReader get (IReadable x) 00316 { 00317 assert (x); 00318 x.read (this); 00319 return this; 00320 } 00321 00322 /*********************************************************************** 00323 00324 Extract a boolean value from the current read-position 00325 00326 ***********************************************************************/ 00327 00328 IReader get (inout bool x) 00329 { 00330 numeric.int1 (&x, x.sizeof); 00331 return this; 00332 } 00333 00334 /*********************************************************************** 00335 00336 Extract an unsigned byte value from the current read-position 00337 00338 ***********************************************************************/ 00339 00340 IReader get (inout ubyte x) 00341 { 00342 numeric.int8u (&x, x.sizeof); 00343 return this; 00344 } 00345 00346 /*********************************************************************** 00347 00348 Extract a byte value from the current read-position 00349 00350 ***********************************************************************/ 00351 00352 IReader get (inout byte x) 00353 { 00354 numeric.int8 (&x, x.sizeof); 00355 return this; 00356 } 00357 00358 /*********************************************************************** 00359 00360 Extract an unsigned short value from the current read-position 00361 00362 ***********************************************************************/ 00363 00364 IReader get (inout ushort x) 00365 { 00366 numeric.int16u (&x, x.sizeof); 00367 return this; 00368 } 00369 00370 /*********************************************************************** 00371 00372 Extract a short value from the current read-position 00373 00374 ***********************************************************************/ 00375 00376 IReader get (inout short x) 00377 { 00378 numeric.int16 (&x, x.sizeof); 00379 return this; 00380 } 00381 00382 /*********************************************************************** 00383 00384 Extract a unsigned int value from the current read-position 00385 00386 ***********************************************************************/ 00387 00388 IReader get (inout uint x) 00389 { 00390 numeric.int32u (&x, x.sizeof); 00391 return this; 00392 } 00393 00394 /*********************************************************************** 00395 00396 Extract an int value from the current read-position 00397 00398 ***********************************************************************/ 00399 00400 IReader get (inout int x) 00401 { 00402 numeric.int32 (&x, x.sizeof); 00403 return this; 00404 } 00405 00406 /*********************************************************************** 00407 00408 Extract an unsigned long value from the current read-position 00409 00410 ***********************************************************************/ 00411 00412 IReader get (inout ulong x) 00413 { 00414 numeric.int64u (&x, x.sizeof); 00415 return this; 00416 } 00417 00418 /*********************************************************************** 00419 00420 Extract a long value from the current read-position 00421 00422 ***********************************************************************/ 00423 00424 IReader get (inout long x) 00425 { 00426 numeric.int64 (&x, x.sizeof); 00427 return this; 00428 } 00429 00430 /*********************************************************************** 00431 00432 Extract a float value from the current read-position 00433 00434 ***********************************************************************/ 00435 00436 IReader get (inout float x) 00437 { 00438 numeric.float32 (&x, x.sizeof); 00439 return this; 00440 } 00441 00442 /*********************************************************************** 00443 00444 Extract a double value from the current read-position 00445 00446 ***********************************************************************/ 00447 00448 IReader get (inout double x) 00449 { 00450 numeric.float64 (&x, x.sizeof); 00451 return this; 00452 } 00453 00454 /*********************************************************************** 00455 00456 Extract a real value from the current read-position 00457 00458 ***********************************************************************/ 00459 00460 IReader get (inout real x) 00461 { 00462 numeric.float80 (&x, x.sizeof); 00463 return this; 00464 } 00465 00466 /*********************************************************************** 00467 00468 Extract a char value from the current read-position 00469 00470 ***********************************************************************/ 00471 00472 IReader get (inout char x) 00473 { 00474 string.char8 (&x, x.sizeof); 00475 return this; 00476 } 00477 00478 /*********************************************************************** 00479 00480 Extract a wide char value from the current read-position 00481 00482 ***********************************************************************/ 00483 00484 IReader get (inout wchar x) 00485 { 00486 string.char16 (&x, x.sizeof); 00487 return this; 00488 } 00489 00490 /*********************************************************************** 00491 00492 Extract a double char value from the current read-position 00493 00494 ***********************************************************************/ 00495 00496 IReader get (inout dchar x) 00497 { 00498 string.char32 (&x, x.sizeof); 00499 return this; 00500 } 00501 00502 /*********************************************************************** 00503 00504 ***********************************************************************/ 00505 00506 final IReader get (inout int[] x) 00507 { 00508 memory.allocate (cast(void[]*) &x, string.char8); 00509 return this; 00510 } 00511 00512 /*********************************************************************** 00513 00514 ***********************************************************************/ 00515 00516 IReader get (inout char[] x) 00517 { 00518 memory.allocate (cast(void[]*) &x, string.char8); 00519 return this; 00520 } 00521 00522 /*********************************************************************** 00523 00524 ***********************************************************************/ 00525 00526 IReader get (inout wchar[] x) 00527 { 00528 memory.allocate (cast(void[]*) &x, string.char16); 00529 return this; 00530 } 00531 00532 /*********************************************************************** 00533 00534 ***********************************************************************/ 00535 00536 IReader get (inout dchar[] x) 00537 { 00538 memory.allocate (cast(void[]*) &x, string.char32); 00539 return this; 00540 } 00541 00542 00543 00544 /**********************************************************************/ 00545 /***************** opShr() is just an alias for get() *****************/ 00546 /**********************************************************************/ 00547 00548 00549 version (UseShiftOperators) 00550 { 00551 /*************************************************************** 00552 00553 ***************************************************************/ 00554 00555 IReader opShr (inout bit x) 00556 { 00557 return get (x); 00558 } 00559 00560 /*************************************************************** 00561 00562 ***************************************************************/ 00563 00564 IReader opShr (inout ubyte x) 00565 { 00566 return get (x); 00567 } 00568 00569 /*************************************************************** 00570 00571 ***************************************************************/ 00572 00573 IReader opShr (inout byte x) 00574 { 00575 return get (x); 00576 } 00577 00578 /*************************************************************** 00579 00580 ***************************************************************/ 00581 00582 IReader opShr (inout ushort x) 00583 { 00584 return get (x); 00585 } 00586 00587 /*************************************************************** 00588 00589 ***************************************************************/ 00590 00591 IReader opShr (inout short x) 00592 { 00593 return get (x); 00594 } 00595 00596 /*************************************************************** 00597 00598 ***************************************************************/ 00599 00600 IReader opShr (inout uint x) 00601 { 00602 return get (x); 00603 } 00604 00605 /*************************************************************** 00606 00607 ***************************************************************/ 00608 00609 IReader opShr (inout int x) 00610 { 00611 return get (x); 00612 } 00613 00614 /*************************************************************** 00615 00616 ***************************************************************/ 00617 00618 IReader opShr (inout ulong x) 00619 { 00620 return get (x); 00621 } 00622 00623 /*************************************************************** 00624 00625 ***************************************************************/ 00626 00627 IReader opShr (inout long x) 00628 { 00629 return get (x); 00630 } 00631 00632 /*************************************************************** 00633 00634 ***************************************************************/ 00635 00636 IReader opShr (inout float x) 00637 { 00638 return get (x); 00639 } 00640 00641 /*************************************************************** 00642 00643 ***************************************************************/ 00644 00645 IReader opShr (inout double x) 00646 { 00647 return get (x); 00648 } 00649 00650 /*************************************************************** 00651 00652 ***************************************************************/ 00653 00654 IReader opShr (inout real x) 00655 { 00656 return get (x); 00657 } 00658 00659 /*************************************************************** 00660 00661 ***************************************************************/ 00662 00663 IReader opShr (IReadable x) 00664 { 00665 return get (x); 00666 } 00667 00668 /*************************************************************** 00669 00670 ***************************************************************/ 00671 00672 IReader opShr (inout char x) 00673 { 00674 return get (x); 00675 } 00676 00677 /*************************************************************** 00678 00679 ***************************************************************/ 00680 00681 IReader opShr (inout wchar x) 00682 { 00683 return get (x); 00684 } 00685 00686 /*************************************************************** 00687 00688 ***************************************************************/ 00689 00690 IReader opShr (inout dchar x) 00691 { 00692 return get (x); 00693 } 00694 00695 /*************************************************************** 00696 00697 ***************************************************************/ 00698 00699 IReader opShr (inout char[] x) 00700 { 00701 return get (x); 00702 } 00703 00704 /*************************************************************** 00705 00706 ***************************************************************/ 00707 00708 IReader opShr (inout wchar[] x) 00709 { 00710 return get (x); 00711 } 00712 00713 /*************************************************************** 00714 00715 ***************************************************************/ 00716 00717 IReader opShr (inout dchar[] x) 00718 { 00719 return get (x); 00720 } 00721 } 00722 } 00723 00724 00725 /+ 00726 /*********************************************************************** 00727 00728 ***********************************************************************/ 00729 00730 template Get (T, alias decoder) 00731 { 00732 IReader get (inout T x) 00733 { 00734 decoder.get (&x, x.sizeof); 00735 return this; 00736 } 00737 } 00738 00739 template GetArray (T, alias decoder) 00740 { 00741 IReader get (inout T x) 00742 { 00743 memory.allocate (cast(void[]*) &x, decoder); 00744 return this; 00745 } 00746 } 00747 00748 mixin Get!(byte, numeric.int8); 00749 //mixin GetArray!(byte[], numeric.int8); 00750 +/