00001 /******************************************************************************* 00002 00003 @file CompositeReader.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, March 2004 00031 @author Kris 00032 00033 00034 *******************************************************************************/ 00035 00036 module mango.io.CompositeReader; 00037 00038 private import mango.io.Exception; 00039 00040 public import mango.io.model.IBuffer, 00041 mango.io.model.IReader; 00042 00043 00044 /******************************************************************************* 00045 00046 CompositeReader 'brackets' the reading of a data set. 00047 00048 The approach leverages the exisiting IReadable interface which, 00049 when implemented, exposes a class that reads a related set of 00050 data. For instance: 00051 00052 @code 00053 class Foo : IReadable 00054 { 00055 int x, 00056 y; 00057 char[] text; 00058 00059 void read (IReader reader) 00060 { 00061 reader.get(x).get(y).get(text); 00062 } 00063 } 00064 @endcode 00065 00066 In the above example, we set up a class that implements IReadable 00067 via the read() method. The class may read whatever it chooses, 00068 and may also invoke the read() method of other IReadable classes. 00069 Thus, the initial IReadable has control over a potential readable 00070 cluster, all of which is bracketed within the CompositeReader. 00071 00072 This CompositeReader ensure it has enough space in the buffer to 00073 read an entire data-set, such that buffer slices mapped into user 00074 space will all be valid. This does not apply where mapping is not 00075 enabled (which is the default setting for all readers). 00076 00077 A word on buffer-mapping: There are a number of situations where 00078 a programmer prefers to avoid the overhead of memory allocation & 00079 subsequent copying of data. Other times, the liveness of content 00080 is more important. The former is attractive in high-performance 00081 systems, whereas the latter is typical of most casual IO. 00082 00083 Most programs won't reap any benefit from buffer-mapping, but may 00084 run afoul of liveness concerns. Therefore, mapping is disabled on 00085 all readers by default. That is, all array types are allocated & 00086 copied as they are read. Change this via Reader.setMapped(). 00087 00088 Note that buffer-mapping applies only to array[] data types. All 00089 integral types are copied directly into local program space. 00090 00091 See CompositeWriter for additional examples. 00092 00093 *******************************************************************************/ 00094 00095 class CompositeReader 00096 { 00097 private int width; 00098 private IReader reader; 00099 00100 /*********************************************************************** 00101 00102 Construct a composite with the given reader. The reader 00103 should be configured for non-mapped input (the default 00104 state for Readers). 00105 00106 ***********************************************************************/ 00107 00108 this (IReader reader) 00109 in { 00110 assert (reader); 00111 } 00112 body 00113 { 00114 this.reader = reader; 00115 } 00116 00117 /*********************************************************************** 00118 00119 Construct a composite with the given reader, and the maximum 00120 width of an input data-set. The width is used to ensure that 00121 an entire data-set will be present in the buffer at one time. 00122 The reader is configured for mapped input. 00123 00124 Use the other constructor(s) for non-mapped input. 00125 00126 ***********************************************************************/ 00127 00128 this (IReader reader, int width) 00129 in { 00130 assert (reader); 00131 assert (width > 0 && width <= reader.getBuffer().getCapacity()); 00132 } 00133 body 00134 { 00135 this.reader = reader; 00136 this.width = width; 00137 00138 // enable mapped arrays 00139 reader.setMapped (true); 00140 } 00141 00142 /*********************************************************************** 00143 00144 Read a data-set, after ensuring there's enough buffer space 00145 for mapping the entire content (where necessary). 00146 00147 ***********************************************************************/ 00148 00149 void get (IReadable target) 00150 in { 00151 assert (target); 00152 } 00153 body 00154 { 00155 IBuffer buffer = reader.getBuffer(); 00156 00157 // ensure we have space for the entire data-set, such that all 00158 // buffer slices are guaranteed to be valid. 00159 if (reader.isMapped() && buffer.readable() < width) 00160 buffer.compress(); 00161 00162 target.read (reader); 00163 } 00164 }