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