00001 /******************************************************************************* 00002 00003 @file Reader.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 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 @version Initial version, October 2004 00034 00035 @author Kris 00036 00037 00038 *******************************************************************************/ 00039 00040 module mango.io.Reader; 00041 00042 private import mango.sys.Type; 00043 00044 private import mango.io.Exception, 00045 mango.io.ArrayAllocator; 00046 00047 public import mango.io.model.IReader, 00048 mango.io.model.IBuffer, 00049 mango.io.model.IConduit; 00050 00051 00052 /******************************************************************************* 00053 00054 Reader base-class. Each reader operates upon an IBuffer, which is 00055 provided at construction time. Said buffer is intended to remain 00056 consistent over the reader lifetime. 00057 00058 All readers support the full set of native data types, plus a full 00059 selection of array types. The latter can be configured to produce 00060 either a copy (.dup) of the buffer content, or a slice. See class 00061 SimpleAllocator, BufferAllocator and SliceAllocator for more on 00062 this topic. 00063 00064 Readers support a C++ iostream type syntax, along with Java-esque 00065 get() notation. However, the Mango style is to place IO elements 00066 within their own parenthesis, like so: 00067 00068 int count; 00069 char[] verse; 00070 00071 read (verse) (count); 00072 00073 Note that each element is distict; this enables "strong typing", 00074 which should catch any typo errors at compile-time. 00075 00076 The code below illustrates basic operation upon a memory buffer: 00077 00078 @code 00079 Buffer buf = new Buffer (256); 00080 00081 // map same buffer into both reader and writer 00082 IReader read = new Reader (buf); 00083 IWriter write = new Writer (buf); 00084 00085 int i = 10; 00086 long j = 20; 00087 double d = 3.14159; 00088 char[] c = "fred"; 00089 00090 // write data types out 00091 write (c) (i) (j) (d); 00092 00093 // read them back again 00094 read (c) (i) (j) (d); 00095 00096 // reset 00097 buf.clear(); 00098 00099 // same thing again, but using iostream syntax instead 00100 write << c << i << j << d; 00101 00102 // read them back again 00103 read >> c >> i >> j >> d; 00104 00105 // reset 00106 buf.clear(); 00107 00108 // same thing again, but using put() syntax instead 00109 write.put(c).put(i).put(j).put(d); 00110 read.get(c).get(i).get(j).get(d); 00111 00112 @endcode 00113 00114 Note that certain Readers, such as the basic binary implementation, 00115 expect to retrieve the number of array elements from the source. 00116 For example; when reading an array from a file, the number of elements 00117 is read from the file also. If the content is not arranged in such a 00118 manner, you may specify how many elements to read via a second argument: 00119 00120 @code 00121 read (myArray, 11); 00122 @endcode 00123 00124 Readers may also be used with any class implementing the IReadable 00125 interface. See PickleReader for an example of how this can be put 00126 to good use. 00127 00128 *******************************************************************************/ 00129 00130 class Reader : SimpleAllocator, IReader 00131 { 00132 /*********************************************************************** 00133 00134 ***********************************************************************/ 00135 00136 union Decoder 00137 { 00138 struct { 00139 BufferDecoder char8, 00140 char16, 00141 char32; 00142 } 00143 BufferDecoder[3] decoders; 00144 } 00145 00146 // the buffer associated with this reader. Note that this 00147 // must not change for the lifetime of the reader, since 00148 // it is assumed to be immutable elsewhere (subclass may 00149 // keep its own copy). 00150 protected IBuffer buffer; 00151 00152 // buffer decoders 00153 protected Decoder decode; 00154 00155 // memory-manager for array requests 00156 private IArrayAllocator memory; 00157 00158 /*********************************************************************** 00159 00160 Construct a Reader upon the provided buffer 00161 00162 ***********************************************************************/ 00163 00164 this (IBuffer buffer) 00165 { 00166 this.buffer = buffer; 00167 00168 decode.char8 = 00169 decode.char16 = 00170 decode.char32 = &read; 00171 00172 setAllocator (this); 00173 } 00174 00175 /*********************************************************************** 00176 00177 Construct a Reader upon the buffer associated with the 00178 given conduit. 00179 00180 ***********************************************************************/ 00181 00182 this (IConduit conduit) 00183 { 00184 this (conduit.createBuffer); 00185 } 00186 00187 /*********************************************************************** 00188 00189 Return the buffer associated with this reader 00190 00191 ***********************************************************************/ 00192 00193 final IBuffer getBuffer () 00194 { 00195 return buffer; 00196 } 00197 00198 /*********************************************************************** 00199 00200 Return the allocator associated with this reader. See 00201 ArrayAllocator for more information. 00202 00203 ***********************************************************************/ 00204 00205 final IArrayAllocator getAllocator () 00206 { 00207 return memory; 00208 } 00209 00210 /*********************************************************************** 00211 00212 Set the allocator to use for array management. Arrays are 00213 always allocated by the IReader. That is, you cannot read 00214 data into an array slice (for example). Instead, a number 00215 of IArrayAllocator classes are available to manage memory 00216 allocation when reading array content. 00217 00218 By default, an IReader will allocate each array from the 00219 heap. You can change that behavior by calling this method 00220 with an IArrayAllocator of choice. For instance, there 00221 is a BufferAllocator which will slice an array directly 00222 from the buffer where possible. Also available is the 00223 record-oriented SliceAllocator, which slices memory from 00224 within a pre-allocated heap area, and should be reset by 00225 the client code after each record has been read (to avoid 00226 unnecessary growth). 00227 00228 See ArrayAllocator for more information. 00229 00230 ***********************************************************************/ 00231 00232 final void setAllocator (IArrayAllocator memory) 00233 { 00234 memory.bind (this); 00235 this.memory = memory; 00236 } 00237 00238 /*********************************************************************** 00239 00240 Bind an IDecoder to the writer. Decoders are intended to 00241 be used as a conversion mechanism between various character 00242 representations (encodings), or the translation of any data 00243 type from one representation to another. Each data type may 00244 be configured with a distinct decoder, covering all native 00245 types (15 in total). 00246 00247 An appropriate decoder set should be attached to each 00248 IReader, and thus be available for subsequent use. A raw 00249 binary implementation is attached by default (no encoding). 00250 00251 See module mango.icu.UMango for an example of decoder 00252 implementation -- those classes bind the ICU converters 00253 to this IO package. 00254 00255 ***********************************************************************/ 00256 00257 final void setDecoder (IDecoder d) 00258 { 00259 decode.decoders[d.type] = d.bind (this); 00260 } 00261 00262 /*********************************************************************** 00263 00264 Read and return an integer from the input stream. This is 00265 used to extract the element count of a subsequent array. 00266 00267 ***********************************************************************/ 00268 00269 private final uint count (uint elements) 00270 { 00271 if (elements == uint.max) 00272 get (elements); 00273 return elements; 00274 } 00275 00276 /*********************************************************************** 00277 00278 Wait for something to arrive in the buffer. This may stall 00279 the current thread forever, although usage of SocketConduit 00280 will take advantage of the timeout facilities provided there. 00281 00282 ***********************************************************************/ 00283 00284 final void wait () 00285 { 00286 buffer.get (1, false); 00287 } 00288 00289 /*********************************************************************** 00290 00291 ***********************************************************************/ 00292 00293 uint read (void *dst, uint bytes, uint type) 00294 { 00295 uint i = bytes; 00296 while (i) 00297 { 00298 // get as much as there is available in the buffer 00299 uint available = buffer.readable(); 00300 00301 // cap bytes read 00302 if (available > i) 00303 available = i; 00304 00305 // copy them over 00306 dst[0..available] = buffer.get (available); 00307 00308 // bump counters 00309 dst += available; 00310 i -= available; 00311 00312 // if we need more, prime the input by reading 00313 if (i) 00314 buffer.get (1, false); 00315 } 00316 return bytes; 00317 } 00318 00319 /*********************************************************************** 00320 00321 Extract a readable class from the current read-position 00322 00323 ***********************************************************************/ 00324 00325 final IReader get (IReadable x) 00326 { 00327 assert (x); 00328 x.read (this); 00329 return this; 00330 } 00331 00332 /*********************************************************************** 00333 00334 Extract a boolean value from the current read-position 00335 00336 ***********************************************************************/ 00337 00338 IReader get (inout bool x) 00339 { 00340 read (&x, x.sizeof, Type.Bool); 00341 return this; 00342 } 00343 00344 /*********************************************************************** 00345 00346 Extract an unsigned byte value from the current read-position 00347 00348 ***********************************************************************/ 00349 00350 IReader get (inout ubyte x) 00351 { 00352 read (&x, x.sizeof, Type.UByte); 00353 return this; 00354 } 00355 00356 /*********************************************************************** 00357 00358 Extract a byte value from the current read-position 00359 00360 ***********************************************************************/ 00361 00362 IReader get (inout byte x) 00363 { 00364 read (&x, x.sizeof, Type.Byte); 00365 return this; 00366 } 00367 00368 /*********************************************************************** 00369 00370 Extract an unsigned short value from the current read-position 00371 00372 ***********************************************************************/ 00373 00374 IReader get (inout ushort x) 00375 { 00376 read (&x, x.sizeof, Type.UShort); 00377 return this; 00378 } 00379 00380 /*********************************************************************** 00381 00382 Extract a short value from the current read-position 00383 00384 ***********************************************************************/ 00385 00386 IReader get (inout short x) 00387 { 00388 read (&x, x.sizeof, Type.Short); 00389 return this; 00390 } 00391 00392 /*********************************************************************** 00393 00394 Extract a unsigned int value from the current read-position 00395 00396 ***********************************************************************/ 00397 00398 IReader get (inout uint x) 00399 { 00400 read (&x, x.sizeof, Type.UInt); 00401 return this; 00402 } 00403 00404 /*********************************************************************** 00405 00406 Extract an int value from the current read-position 00407 00408 ***********************************************************************/ 00409 00410 IReader get (inout int x) 00411 { 00412 read (&x, x.sizeof, Type.Int); 00413 return this; 00414 } 00415 00416 /*********************************************************************** 00417 00418 Extract an unsigned long value from the current read-position 00419 00420 ***********************************************************************/ 00421 00422 IReader get (inout ulong x) 00423 { 00424 read (&x, x.sizeof, Type.ULong); 00425 return this; 00426 } 00427 00428 /*********************************************************************** 00429 00430 Extract a long value from the current read-position 00431 00432 ***********************************************************************/ 00433 00434 IReader get (inout long x) 00435 { 00436 read (&x, x.sizeof, Type.Long); 00437 return this; 00438 } 00439 00440 /*********************************************************************** 00441 00442 Extract a float value from the current read-position 00443 00444 ***********************************************************************/ 00445 00446 IReader get (inout float x) 00447 { 00448 read (&x, x.sizeof, Type.Float); 00449 return this; 00450 } 00451 00452 /*********************************************************************** 00453 00454 Extract a double value from the current read-position 00455 00456 ***********************************************************************/ 00457 00458 IReader get (inout double x) 00459 { 00460 read (&x, x.sizeof, Type.Double); 00461 return this; 00462 } 00463 00464 /*********************************************************************** 00465 00466 Extract a real value from the current read-position 00467 00468 ***********************************************************************/ 00469 00470 IReader get (inout real x) 00471 { 00472 read (&x, x.sizeof, Type.Real); 00473 return this; 00474 } 00475 00476 /*********************************************************************** 00477 00478 Extract a char value from the current read-position 00479 00480 ***********************************************************************/ 00481 00482 IReader get (inout char x) 00483 { 00484 decode.char8 (&x, x.sizeof, Type.Utf8); 00485 return this; 00486 } 00487 00488 /*********************************************************************** 00489 00490 Extract a wide char value from the current read-position 00491 00492 ***********************************************************************/ 00493 00494 IReader get (inout wchar x) 00495 { 00496 decode.char16 (&x, x.sizeof, Type.Utf16); 00497 return this; 00498 } 00499 00500 /*********************************************************************** 00501 00502 Extract a double char value from the current read-position 00503 00504 ***********************************************************************/ 00505 00506 IReader get (inout dchar x) 00507 { 00508 decode.char32 (&x, x.sizeof, Type.Utf32); 00509 return this; 00510 } 00511 00512 /*********************************************************************** 00513 00514 Extract an unsigned byte array from the current read-position 00515 00516 ***********************************************************************/ 00517 00518 IReader get (inout ubyte[] x, uint elements = uint.max) 00519 { 00520 memory.allocate (cast(void[]*) &x, count(elements)*ubyte.sizeof, 00521 ubyte.sizeof, Type.UByte, &read); 00522 return this; 00523 } 00524 00525 /*********************************************************************** 00526 00527 Extract a byte array from the current read-position 00528 00529 ***********************************************************************/ 00530 00531 IReader get (inout byte[] x, uint elements = uint.max) 00532 { 00533 memory.allocate (cast(void[]*) &x, count(elements)*byte.sizeof, 00534 byte.sizeof, Type.Byte, &read); 00535 return this; 00536 } 00537 00538 /*********************************************************************** 00539 00540 Extract an unsigned short array from the current read-position 00541 00542 ***********************************************************************/ 00543 00544 IReader get (inout ushort[] x, uint elements = uint.max) 00545 { 00546 memory.allocate (cast(void[]*) &x, count(elements)*ushort.sizeof, 00547 ushort.sizeof, Type.UShort, &read); 00548 return this; 00549 } 00550 00551 /*********************************************************************** 00552 00553 Extract a short array from the current read-position 00554 00555 ***********************************************************************/ 00556 00557 IReader get (inout short[] x, uint elements = uint.max) 00558 { 00559 memory.allocate (cast(void[]*) &x, count(elements)*short.sizeof, 00560 short.sizeof, Type.Short, &read); 00561 return this; 00562 } 00563 00564 /*********************************************************************** 00565 00566 Extract a unsigned int array from the current read-position 00567 00568 ***********************************************************************/ 00569 00570 IReader get (inout uint[] x, uint elements = uint.max) 00571 { 00572 memory.allocate (cast(void[]*) &x, count(elements)*uint.sizeof, 00573 uint.sizeof, Type.UInt, &read); 00574 return this; 00575 } 00576 00577 /*********************************************************************** 00578 00579 Extract an int array from the current read-position 00580 00581 ***********************************************************************/ 00582 00583 IReader get (inout int[] x, uint elements = uint.max) 00584 { 00585 memory.allocate (cast(void[]*) &x, count(elements)*int.sizeof, 00586 int.sizeof, Type.Int, &read); 00587 return this; 00588 } 00589 00590 /*********************************************************************** 00591 00592 Extract an unsigned long array from the current read-position 00593 00594 ***********************************************************************/ 00595 00596 IReader get (inout ulong[] x, uint elements = uint.max) 00597 { 00598 memory.allocate (cast(void[]*) &x, count(elements)*ulong.sizeof, 00599 ulong.sizeof, Type.ULong, &read); 00600 return this; 00601 } 00602 00603 /*********************************************************************** 00604 00605 Extract a long array from the current read-position 00606 00607 ***********************************************************************/ 00608 00609 IReader get (inout long[] x, uint elements = uint.max) 00610 { 00611 memory.allocate (cast(void[]*) &x, count(elements)*long.sizeof, 00612 long.sizeof, Type.Long, &read); 00613 return this; 00614 } 00615 00616 /*********************************************************************** 00617 00618 Extract a float array from the current read-position 00619 00620 ***********************************************************************/ 00621 00622 IReader get (inout float[] x, uint elements = uint.max) 00623 { 00624 memory.allocate (cast(void[]*) &x, count(elements)*float.sizeof, 00625 float.sizeof, Type.Float, &read); 00626 return this; 00627 } 00628 00629 /*********************************************************************** 00630 00631 Extract a double array from the current read-position 00632 00633 ***********************************************************************/ 00634 00635 IReader get (inout double[] x, uint elements = uint.max) 00636 { 00637 memory.allocate (cast(void[]*) &x, count(elements)*double.sizeof, 00638 double.sizeof, Type.Double, &read); 00639 return this; 00640 } 00641 00642 /*********************************************************************** 00643 00644 Extract a real array from the current read-position 00645 00646 ***********************************************************************/ 00647 00648 IReader get (inout real[] x, uint elements = uint.max) 00649 { 00650 memory.allocate (cast(void[]*) &x, count(elements)*real.sizeof, 00651 real.sizeof, Type.Real, &read); 00652 return this; 00653 } 00654 00655 /*********************************************************************** 00656 00657 ***********************************************************************/ 00658 00659 IReader get (inout char[] x, uint elements = uint.max) 00660 { 00661 memory.allocate (cast(void[]*) &x, count(elements)*char.sizeof, 00662 char.sizeof, Type.Utf8, decode.char8); 00663 return this; 00664 } 00665 00666 /*********************************************************************** 00667 00668 ***********************************************************************/ 00669 00670 IReader get (inout wchar[] x, uint elements = uint.max) 00671 { 00672 memory.allocate (cast(void[]*) &x, count(elements)*wchar.sizeof, 00673 wchar.sizeof, Type.Utf16, decode.char16); 00674 return this; 00675 } 00676 00677 /*********************************************************************** 00678 00679 ***********************************************************************/ 00680 00681 IReader get (inout dchar[] x, uint elements = uint.max) 00682 { 00683 memory.allocate (cast(void[]*) &x, count(elements)*dchar.sizeof, 00684 dchar.sizeof, Type.Utf32, decode.char32); 00685 return this; 00686 } 00687 }