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 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 get() 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 Readers may also be used with any class implementing the IReadable 00091 interface. See PickleReader for an example of how this can be put 00092 to good use. 00093 00094 *******************************************************************************/ 00095 00096 class AbstractReader : SimpleAllocator, IReader 00097 { 00098 /*********************************************************************** 00099 00100 ***********************************************************************/ 00101 00102 struct NumericDecoder 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 StringDecoder 00123 { 00124 BufferConverter char8, 00125 char16, 00126 char32; 00127 } 00128 00129 // a couple of pre-constructed exceptions 00130 private static EofException eof; 00131 private static IOException udf; 00132 00133 // the buffer associated with this reader. Note that this 00134 // must not change for the lifetime of the reader, since 00135 // it is assumed to be immutable elsewhere (subclass may 00136 // keep its own copy). 00137 protected IBuffer buffer; 00138 00139 // decoders for string requests 00140 protected StringDecoder string; 00141 00142 // decoders for numeric requests 00143 protected NumericDecoder numeric; 00144 00145 // memory-manager for array requests 00146 private IArrayAllocator memory; 00147 00148 // size for client-specified allocations 00149 private uint pushed = uint.max; 00150 00151 /*********************************************************************** 00152 00153 Return the name of this reader 00154 00155 ***********************************************************************/ 00156 00157 abstract char[] toString (); 00158 00159 /*********************************************************************** 00160 00161 Construct a couple of static exception instances. 00162 00163 ***********************************************************************/ 00164 00165 static this () 00166 { 00167 eof = new EofException ("premature end-of-input"); 00168 udf = new IOException ("input buffer underflow"); 00169 } 00170 00171 /*********************************************************************** 00172 00173 Return the buffer associated with this reader 00174 00175 ***********************************************************************/ 00176 00177 this (IBuffer buffer) 00178 { 00179 super (this); 00180 this.memory = this; 00181 this.buffer = buffer; 00182 } 00183 00184 /*********************************************************************** 00185 00186 Return the buffer associated with this reader 00187 00188 ***********************************************************************/ 00189 00190 final IBuffer getBuffer () 00191 { 00192 return buffer; 00193 } 00194 00195 /*********************************************************************** 00196 00197 Return the allocator associated with this reader.See 00198 ArrayAllocator for more information. 00199 00200 ***********************************************************************/ 00201 00202 final IArrayAllocator getAllocator () 00203 { 00204 return memory; 00205 } 00206 00207 /*********************************************************************** 00208 00209 Set the allocator to use for array management. Arrays are 00210 always allocated by the IReader. That is, you cannot read 00211 data into an array slice (for example). Instead, a number 00212 of IArrayAllocator classes are available to manage memory 00213 allocation when reading array content. 00214 00215 By default, an IReader will allocate each array from the 00216 heap. You can change that behavior by calling this method 00217 with an IArrayAllocator of choice. For instance, there 00218 is a BufferAllocator which will slice an array directly 00219 from the buffer where possible. Also available is the 00220 record-oriented SliceAllocator, which slices memory from 00221 within a pre-allocated heap area, and should be reset by 00222 the client code after each record has been read (to avoid 00223 unnecessary growth). 00224 00225 See ArrayAllocator for more information. 00226 00227 ***********************************************************************/ 00228 00229 final void setAllocator (IArrayAllocator memory) 00230 { 00231 if (! memory) 00232 memory = this; 00233 this.memory = memory; 00234 } 00235 00236 /*********************************************************************** 00237 00238 Set the configured IStringDecoder. These are intended to 00239 be used as a conversion mechanism between various character 00240 representations. They are also expected to be used for the 00241 process of applying character encodings. 00242 00243 See IStringDecoder. 00244 00245 ***********************************************************************/ 00246 00247 final void setStringDecoder (IStringDecoder s) 00248 { 00249 string.char8 = &s.char8; 00250 string.char16 = &s.char16; 00251 string.char32 = &s.char32; 00252 } 00253 00254 /*********************************************************************** 00255 00256 Push the size (in bytes) to use for the next array-read. 00257 By default, array sizes are read from the input stream, 00258 so this is the means by which one may specify the size 00259 where the stream is not formatted in such a manner. 00260 00261 @code 00262 char[] x; 00263 int size; 00264 IReader reader; 00265 00266 reader.push(size).get(x); 00267 @endcode 00268 00269 ***********************************************************************/ 00270 00271 final IReader push (uint size) 00272 { 00273 if (pushed == uint.max) 00274 pushed = size; 00275 else 00276 throw new IOException ("invalid IReader push-sequence"); 00277 return this; 00278 } 00279 00280 /*********************************************************************** 00281 00282 Read and return an integer from the input stream. This can 00283 be used to extract the length of a subsequent array. 00284 00285 ***********************************************************************/ 00286 00287 final uint length () 00288 { 00289 uint len = pushed; 00290 00291 if (len != uint.max) 00292 pushed = uint.max; 00293 else 00294 get (len); 00295 return len; 00296 } 00297 00298 /*********************************************************************** 00299 00300 Wait for something to arrive in the buffer. This may stall 00301 the current thread forever, although usage of SocketConduit 00302 will take advantage of the timeout facilities provided there. 00303 00304 ***********************************************************************/ 00305 00306 final void wait () 00307 { 00308 buffer.get (1, false); 00309 } 00310 00311 /*********************************************************************** 00312 00313 Extract a readable class from the current read-position 00314 00315 ***********************************************************************/ 00316 00317 final IReader get (IReadable x) 00318 { 00319 assert (x); 00320 x.read (this); 00321 return this; 00322 } 00323 00324 /*********************************************************************** 00325 00326 Extract a boolean value from the current read-position 00327 00328 ***********************************************************************/ 00329 00330 IReader get (inout bool x) 00331 { 00332 numeric.int1 (&x, x.sizeof); 00333 return this; 00334 } 00335 00336 /*********************************************************************** 00337 00338 Extract an unsigned byte value from the current read-position 00339 00340 ***********************************************************************/ 00341 00342 IReader get (inout ubyte x) 00343 { 00344 numeric.int8u (&x, x.sizeof); 00345 return this; 00346 } 00347 00348 /*********************************************************************** 00349 00350 Extract a byte value from the current read-position 00351 00352 ***********************************************************************/ 00353 00354 IReader get (inout byte x) 00355 { 00356 numeric.int8 (&x, x.sizeof); 00357 return this; 00358 } 00359 00360 /*********************************************************************** 00361 00362 Extract an unsigned short value from the current read-position 00363 00364 ***********************************************************************/ 00365 00366 IReader get (inout ushort x) 00367 { 00368 numeric.int16u (&x, x.sizeof); 00369 return this; 00370 } 00371 00372 /*********************************************************************** 00373 00374 Extract a short value from the current read-position 00375 00376 ***********************************************************************/ 00377 00378 IReader get (inout short x) 00379 { 00380 numeric.int16 (&x, x.sizeof); 00381 return this; 00382 } 00383 00384 /*********************************************************************** 00385 00386 Extract a unsigned int value from the current read-position 00387 00388 ***********************************************************************/ 00389 00390 IReader get (inout uint x) 00391 { 00392 numeric.int32u (&x, x.sizeof); 00393 return this; 00394 } 00395 00396 /*********************************************************************** 00397 00398 Extract an int value from the current read-position 00399 00400 ***********************************************************************/ 00401 00402 IReader get (inout int x) 00403 { 00404 numeric.int32 (&x, x.sizeof); 00405 return this; 00406 } 00407 00408 /*********************************************************************** 00409 00410 Extract an unsigned long value from the current read-position 00411 00412 ***********************************************************************/ 00413 00414 IReader get (inout ulong x) 00415 { 00416 numeric.int64u (&x, x.sizeof); 00417 return this; 00418 } 00419 00420 /*********************************************************************** 00421 00422 Extract a long value from the current read-position 00423 00424 ***********************************************************************/ 00425 00426 IReader get (inout long x) 00427 { 00428 numeric.int64 (&x, x.sizeof); 00429 return this; 00430 } 00431 00432 /*********************************************************************** 00433 00434 Extract a float value from the current read-position 00435 00436 ***********************************************************************/ 00437 00438 IReader get (inout float x) 00439 { 00440 numeric.float32 (&x, x.sizeof); 00441 return this; 00442 } 00443 00444 /*********************************************************************** 00445 00446 Extract a double value from the current read-position 00447 00448 ***********************************************************************/ 00449 00450 IReader get (inout double x) 00451 { 00452 numeric.float64 (&x, x.sizeof); 00453 return this; 00454 } 00455 00456 /*********************************************************************** 00457 00458 Extract a real value from the current read-position 00459 00460 ***********************************************************************/ 00461 00462 IReader get (inout real x) 00463 { 00464 numeric.float80 (&x, x.sizeof); 00465 return this; 00466 } 00467 00468 /*********************************************************************** 00469 00470 Extract a char value from the current read-position 00471 00472 ***********************************************************************/ 00473 00474 IReader get (inout char x) 00475 { 00476 string.char8 (&x, x.sizeof); 00477 return this; 00478 } 00479 00480 /*********************************************************************** 00481 00482 Extract a wide char value from the current read-position 00483 00484 ***********************************************************************/ 00485 00486 IReader get (inout wchar x) 00487 { 00488 string.char16 (&x, x.sizeof); 00489 return this; 00490 } 00491 00492 /*********************************************************************** 00493 00494 Extract a double char value from the current read-position 00495 00496 ***********************************************************************/ 00497 00498 IReader get (inout dchar x) 00499 { 00500 string.char32 (&x, x.sizeof); 00501 return this; 00502 } 00503 00504 /*********************************************************************** 00505 00506 ***********************************************************************/ 00507 00508 final IReader get (inout int[] x) 00509 { 00510 memory.allocate (cast(void[]*) &x, string.char8); 00511 return this; 00512 } 00513 00514 /*********************************************************************** 00515 00516 ***********************************************************************/ 00517 00518 IReader get (inout char[] x) 00519 { 00520 memory.allocate (cast(void[]*) &x, string.char8); 00521 return this; 00522 } 00523 00524 /*********************************************************************** 00525 00526 ***********************************************************************/ 00527 00528 IReader get (inout wchar[] x) 00529 { 00530 memory.allocate (cast(void[]*) &x, string.char16); 00531 return this; 00532 } 00533 00534 /*********************************************************************** 00535 00536 ***********************************************************************/ 00537 00538 IReader get (inout dchar[] x) 00539 { 00540 memory.allocate (cast(void[]*) &x, string.char32); 00541 return this; 00542 } 00543 00544 00545 00546 /**********************************************************************/ 00547 /***************** opShr() is just an alias for get() *****************/ 00548 /**********************************************************************/ 00549 00550 00551 version (UseShiftOperators) 00552 { 00553 /*************************************************************** 00554 00555 ***************************************************************/ 00556 00557 IReader opShr (inout bit x) 00558 { 00559 return get (x); 00560 } 00561 00562 /*************************************************************** 00563 00564 ***************************************************************/ 00565 00566 IReader opShr (inout ubyte x) 00567 { 00568 return get (x); 00569 } 00570 00571 /*************************************************************** 00572 00573 ***************************************************************/ 00574 00575 IReader opShr (inout byte x) 00576 { 00577 return get (x); 00578 } 00579 00580 /*************************************************************** 00581 00582 ***************************************************************/ 00583 00584 IReader opShr (inout ushort x) 00585 { 00586 return get (x); 00587 } 00588 00589 /*************************************************************** 00590 00591 ***************************************************************/ 00592 00593 IReader opShr (inout short x) 00594 { 00595 return get (x); 00596 } 00597 00598 /*************************************************************** 00599 00600 ***************************************************************/ 00601 00602 IReader opShr (inout uint x) 00603 { 00604 return get (x); 00605 } 00606 00607 /*************************************************************** 00608 00609 ***************************************************************/ 00610 00611 IReader opShr (inout int x) 00612 { 00613 return get (x); 00614 } 00615 00616 /*************************************************************** 00617 00618 ***************************************************************/ 00619 00620 IReader opShr (inout ulong x) 00621 { 00622 return get (x); 00623 } 00624 00625 /*************************************************************** 00626 00627 ***************************************************************/ 00628 00629 IReader opShr (inout long x) 00630 { 00631 return get (x); 00632 } 00633 00634 /*************************************************************** 00635 00636 ***************************************************************/ 00637 00638 IReader opShr (inout float x) 00639 { 00640 return get (x); 00641 } 00642 00643 /*************************************************************** 00644 00645 ***************************************************************/ 00646 00647 IReader opShr (inout double x) 00648 { 00649 return get (x); 00650 } 00651 00652 /*************************************************************** 00653 00654 ***************************************************************/ 00655 00656 IReader opShr (inout real x) 00657 { 00658 return get (x); 00659 } 00660 00661 /*************************************************************** 00662 00663 ***************************************************************/ 00664 00665 IReader opShr (IReadable x) 00666 { 00667 return get (x); 00668 } 00669 00670 /*************************************************************** 00671 00672 ***************************************************************/ 00673 00674 IReader opShr (inout char x) 00675 { 00676 return get (x); 00677 } 00678 00679 /*************************************************************** 00680 00681 ***************************************************************/ 00682 00683 IReader opShr (inout wchar x) 00684 { 00685 return get (x); 00686 } 00687 00688 /*************************************************************** 00689 00690 ***************************************************************/ 00691 00692 IReader opShr (inout dchar x) 00693 { 00694 return get (x); 00695 } 00696 00697 /*************************************************************** 00698 00699 ***************************************************************/ 00700 00701 IReader opShr (inout char[] x) 00702 { 00703 return get (x); 00704 } 00705 00706 /*************************************************************** 00707 00708 ***************************************************************/ 00709 00710 IReader opShr (inout wchar[] x) 00711 { 00712 return get (x); 00713 } 00714 00715 /*************************************************************** 00716 00717 ***************************************************************/ 00718 00719 IReader opShr (inout dchar[] x) 00720 { 00721 return get (x); 00722 } 00723 } 00724 } 00725 00726 00727 /+ 00728 /*********************************************************************** 00729 00730 ***********************************************************************/ 00731 00732 template Get (T, alias decoder) 00733 { 00734 IReader get (inout T x) 00735 { 00736 decoder.get (&x, x.sizeof); 00737 return this; 00738 } 00739 } 00740 00741 template GetArray (T, alias decoder) 00742 { 00743 IReader get (inout T x) 00744 { 00745 memory.allocate (cast(void[]*) &x, decoder); 00746 return this; 00747 } 00748 } 00749 00750 mixin Get!(byte, numeric.int8); 00751 //mixin GetArray!(byte[], numeric.int8); 00752 +/