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