Changeset 898
- Timestamp:
- 05/29/06 18:19:25 (2 years ago)
- Files:
-
- trunk/mango/io/Buffer.d (modified) (20 diffs)
- trunk/mango/io/model/IBuffer.d (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/mango/io/Buffer.d
r798 r898 1 1 /******************************************************************************* 2 2 3 @file Buffer.d 4 5 Copyright (c) 2004 Kris Bell 3 file: _Buffer.d 4 5 copyright: (c) 2004 Kris Bell; all rights reserved 6 7 authors: Kris 8 9 version: Initial version; March 2004 10 11 license: BSD style 6 12 7 13 This software is provided 'as-is', without any express or implied … … 22 28 23 29 3. This notice may not be removed or altered from any distribution 24 of the source. 25 26 4. Derivative works are permitted, but they must carry this notice 27 in full and credit the original source. 28 29 30 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 32 33 @version Initial version; March 2004 34 35 @author Kris 36 30 of the source, and applies to all variations including, but not 31 limited to, original source, derived source, and altered source. 32 33 Copyright (c) 2004 Kris Bell; all rights reserved 37 34 38 35 *******************************************************************************/ … … 53 50 extern (C) 54 51 { 55 void * memcpy (void *dst, void *src, uint);52 private void * memcpy (void *dst, void *src, uint); 56 53 } 57 54 58 55 /******************************************************************************* 59 56 60 The basic premise behind this IO package is as follows: 61 62 @li The central concept is that of a buffer. The buffer acts 63 as a queue (line) where items are removed from the front 64 and new items are added to the back. Buffers are modeled 65 by mango.io.model.IBuffer, and a concrete implementation is 66 provided this class. 67 68 @li Buffers can be written to directly, but a Reader and/or 69 Writer are typically used to read & write formatted data. 70 These readers & writers are bound to a specific buffer; 71 often the same buffer. It's also perfectly legitimate to 72 bind multiple writers to the same buffer; they will all 73 behave serially as one would expect. The same applies to 74 multiple readers on the same buffer. Readers and writers 75 support three styles of IO: put/get, the C++ style << & 76 >> operators, and the () whisper style. All operations 77 can be chained. 78 79 @li Any class can be made compatable with the reader/writer 80 framework by implementing the IReadable and/or IWritable 81 interfaces. Each of these specify just a single method. 82 Once compatable, the class can simply be passed to the 83 reader/writer as if it were native data. 84 85 @li Buffers may also be tokenized. This is handy when one is 86 dealing with text input, and/or the content suits a more 87 fluid format than most typical readers & writers support. 88 Tokens are mapped directly onto buffer content, so there 89 is only minor overhead in using them. Tokens can be read 90 and written by reader/writers also, using a more relaxed 91 set of rules than those applied to discrete I/O. 92 93 @li Buffers are sometimes memory-only, in which case there 94 is nothing left to do when a reader (or tokenizer) hits 95 end of buffer conditions. Other buffers are themselves 96 bound to a Conduit. When this is the case, a reader will 97 eventually cause the buffer to reload via its associated 98 conduit. Previous buffer content will thus be lost. The 99 same concept is applied to writers, whereby they flush 100 the content of a full buffer to a bound conduit before 101 continuing. 102 103 @li Conduits provide virtualized access to external content, 104 and represent things like files or Internet connections. 105 They are just a different kind of stream. Conduits are 106 modelled by mango.io.model.IConduit, and implemented via 107 classes FileConduit and SocketConduit. Additional kinds 108 of conduit are easy to construct: one either subclasses 109 mango.io.Conduit, or implements mango.io.model.IConduit. 110 A conduit reads and writes from/to a buffer in big chunks 111 (typically the entire buffer). 112 113 @li Conduits may have one or more filters attached. These 114 will process content as it flows back and forth across 115 the conduit. Filter examples include compression, utf 116 transcoding, and endian transformation. These filters 117 apply to the entire scope of the conduit, rather than 118 being specific to one data-type or another. 119 120 @li Readers & writers may have a transcoder attached. The 121 role of a transcoder is to aid in converting between each 122 representation of text (utf8, utf16, utf32). They're used 123 to normalize string I/O according to a standard text-type. 124 By default there is no transcoder attached, and the type 125 is therefore considered "raw". 126 127 128 An example of how to append a buffer follows: 129 130 @code 131 char[] foo = "to write some D"; 132 57 The premise behind this IO package is as follows: 58 59 The central concept is that of a buffer. The buffer acts 60 as a queue (line) where items are removed from the front 61 and new items are added to the back. Buffers are modeled 62 by mango.io.model.IBuffer, and a concrete implementation 63 is provided by this class. 64 65 Buffers can be read and written directly, but a Reader, 66 Iterator, and/or Writer are often leveraged to apply 67 structure to what might otherwise be simple raw data. 68 69 Readers & writers are bound to a buffer; often the same 70 buffer. It's also perfectly legitimate to bind multiple 71 readers to the same buffer; they will access buffer 72 content serially as one would expect. This also applies to 73 multiple writers on the same buffer. Readers and writers 74 support three styles of IO: put/get, the C++ style << & 75 >> operators, and the () whisper style. All operations 76 can be chained. 77 78 Any class can be made compatable with the reader/writer 79 framework by implementing the IReadable and/or IWritable 80 interfaces. Each of these specify just a single method. 81 Once compatable, the class can simply be passed to the 82 reader/writer as if it were native data. 83 84 Buffers may also be tokenized by applying an Iterator. 85 This can be handy when one is dealing with text input, 86 and/or the content suits a more fluid format than most 87 typical readers & writers support. Iterator tokens 88 are mapped directly onto buffer content (sliced), making 89 them quite efficient in practice. Like Readers, multiple 90 iterators can be mapped onto a common buffer; access is 91 serialized in a similar fashion. 92 93 Conduits provide virtualized access to external content, 94 and represent things like files or Internet connections. 95 They are just a different kind of stream. Conduits are 96 modelled by mango.io.model.IConduit, and implemented via 97 classes FileConduit, SocketConduit, ConsoleConduit, and 98 so on. Additional conduit varieties are easy to construct: 99 one either subclasses mango.io.Conduit, or implements 100 mango.io.model.IConduit. Each conduit reads and writes 101 from/to a buffer in big chunks (typically the entire 102 buffer). 103 104 Conduits may have one or more filters attached. These 105 will process content as it flows back and forth across 106 the conduit. Examples of filters include compression, utf 107 transcoding, and endian transformation. These filters 108 apply to the entire scope of the conduit, rather than 109 being specific to one data-type or another. Specific 110 data-type transformations are applied by readers and 111 writers instead, and include operations such as 112 endian-conversion. 113 114 Buffers are sometimes memory-only, in which case there 115 is nothing left to do when a reader (or iterator) hits 116 end of buffer conditions. Other buffers are themselves 117 bound to a Conduit. When this is the case, a reader will 118 eventually cause the buffer to reload via its associated 119 conduit. Previous buffer content will thus be lost. The 120 same approach is applied to writers, whereby they flush 121 the content of a full buffer to a bound conduit before 122 continuing. Another variation is that of a memory-mapped 123 buffer, whereby the buffer content is mapped directly to 124 virtual memory exposed via the oS. This can be used to 125 address large files as an array of content. 126 127 Readers & writers may have a transcoder attached. The 128 role of a transcoder is to aid in converting between each 129 representation of text (utf8, utf16, utf32). They're used 130 to normalize string I/O according to a standard text-type. 131 By default there is no transcoder attached, and the type 132 is therefore considered "raw". 133 134 Direct buffer manipulation typically involves appending, 135 as in the following example: 136 --- 133 137 // create a small buffer 134 138 auto buf = new Buffer (256); 135 139 140 auto foo = "to write some D"; 141 136 142 // append some text directly to it 137 143 buf.append("now is the time for all good men ").append(foo); 138 139 // output the combined string 140 Cout (buf.toString); 141 @endcode 142 143 Alternatively, one might use a Writer to append the buffer: 144 145 @code 144 --- 145 146 Alternatively, one might use a Writer to append the buffer. 147 This is an example of the 'whisper' style supported by the 148 IO package: 149 --- 146 150 auto write = new Writer (new Buffer(256)); 147 151 write ("now is the time for all good men "c) (foo); 148 @endcode 149 150 Or, using printf-like formatting: 151 152 @code 152 --- 153 154 Or, using printf-like formatting via a text oriented DisplayWriter: 155 --- 153 156 auto write = new DisplayWriter (new Buffer(256)); 154 157 write.print ("now is the time for %d good men %s", 3, foo); 155 @endcode156 157 You might use a GrowBuffer instead where you wish to158 append beyond a preset limit. One common usage of buffers159 is in conjunction with a conduit, such as FileConduit. Each160 conduit exposes a preferred-size for its associated buffers,161 utilized during Buffer construction:162 163 @code158 --- 159 160 One might use a GrowBuffer instead, where one wishes to append 161 beyond the specified size. 162 163 A common usage of a buffer is in conjunction with a conduit, 164 such as FileConduit. Each conduit exposes a preferred-size for 165 its associated buffers, utilized during buffer construction: 166 --- 164 167 auto file = new FileConduit ("file.name"); 165 168 auto buf = new Buffer (file); 166 @endcode169 --- 167 170 168 171 However, this is typically hidden by higher level constructors 169 172 such as those of Reader and Writer derivitives. For example: 170 171 @code 173 --- 172 174 auto file = new FileConduit ("file.name"); 173 175 auto read = new Reader (file); 174 @endcode176 --- 175 177 176 178 There is indeed a buffer between the Reader and Conduit, but 177 explicit construction is unecessary in most cases.See both179 explicit construction is unecessary in common cases. See both 178 180 Reader and Writer for examples of formatted IO. 179 181 180 182 Stdout is a predefined DisplayWriter, attached to a conduit 181 183 representing the console. Thus, all conduit operations are 182 legitimate on Stdout and Stderr: 183 184 @code 184 legitimate on Stdout and Stderr. For example: 185 --- 185 186 Stdout.conduit.copy (new FileConduit ("readme.txt")); 186 @endcode187 188 In addition to the standard writer facilities, Stdout also has187 --- 188 189 Because Stdout is an instance of DisplayWriter, it also has 189 190 support for formatted output: 190 191 @code 191 --- 192 192 Stdout.println ("now is the time for %d good men %s", 3, foo); 193 @endcode 193 --- 194 195 The Stdout writer is attached to a specific buffer, which in 196 turn is attached to a specific conduit. This buffer is known 197 as Cout, and it is attached to a conduit representing the 198 console. Cout can be used directly, bypassing the writer layer 199 if so desired. 200 201 Cout has relatives named Cerr and Cin, which are attached to 202 the corresponding console conduits. Writer Stderr, and reader 203 Stdin are mapped onto Cerr and Cin respectively, ensuring 204 console IO is buffered in one common area. 205 --- 206 Cout ("what is your name?"); 207 char[] name; 208 Cin (name); 209 Cout ("hello ") (name) .newline; 210 --- 211 212 An Iterator is constructed in a similar manner to a Reader; you 213 provide it with a buffer or a conduit. There's a variety of 214 iterators available in the mango.text package, and they are each 215 templated for utf8, utf16, and utf32 ~ this example uses a line 216 iterator to sweep a text file: 217 --- 218 auto file = new FileConduit ("file.name"); 219 foreach (line; new LineIterator (file)) 220 Cout(line).newline; 221 --- 194 222 195 223 Buffers are useful for many purposes within Mango, but there 196 are times when it is more straightforward to avoid them. For197 such cases, conduit derivatives (such as FileConduit) support 198 direct I/O via a pair of read() and write() methods. These199 alternate methods will also invoke any attached filters.224 are times when it may be more appropriate to sidestep them. For 225 such cases, conduit derivatives (such as FileConduit) support 226 direct array-based IO via a pair of read() and write() methods. 227 These alternate methods will also invoke any attached filters. 200 228 201 229 … … 204 232 class Buffer : IBuffer 205 233 { 206 protected void[] data; 207 protected Style style; 208 protected uint limit; 209 protected uint capacity; 210 protected uint position; 211 protected IConduit conduit; 212 234 protected void[] data; // the raw data 235 protected Style style; // Text, Binary, Raw 236 protected uint limit; // limit of valid content 237 protected uint capacity; // maximum of limit 238 protected uint position; // current read position 239 protected IConduit conduit; // optional conduit 240 241 213 242 protected static char[] overflow = "output buffer overflow"; 214 243 protected static char[] underflow = "input buffer underflow"; … … 230 259 /*********************************************************************** 231 260 232 Construct a Buffer upon the provided conduit 261 Construct a Buffer upon the provided conduit. A relevant 262 buffer size is supplied via the provided conduit. 233 263 234 264 ***********************************************************************/ … … 243 273 /*********************************************************************** 244 274 245 Construct a Buffer with the specified number of bytes. 246 247 ***********************************************************************/ 248 249 this (uint capacity =0)275 Construct a Buffer with the specified number of bytes. 276 277 ***********************************************************************/ 278 279 this (uint capacity = 0) 250 280 { 251 281 this (new ubyte[capacity]); … … 291 321 /*********************************************************************** 292 322 293 Return the backing array 294 295 ***********************************************************************/ 296 297 protected void[] getContent () 298 { 299 return data; 300 } 301 302 /*********************************************************************** 303 304 Return style of buffer 323 Return style of buffer. This is either Text, Binary, or Raw. 324 The style is initially set via a constructor 305 325 306 326 ***********************************************************************/ … … 315 335 Set the backing array with all content readable. Writing 316 336 to this will either flush it to an associated conduit, or 317 raise an Eof condition. Use IBuffer.clear() to reset the337 raise an Eof condition. Use clear() to reset the 318 338 content (make it all writable). 319 339 … … 329 349 Set the backing array with some content readable. Writing 330 350 to this will either flush it to an associated conduit, or 331 raise an Eof condition. Use IBuffer.clear() to reset the351 raise an Eof condition. Use clear() to reset the 332 352 content (make it all writable). 333 353 … … 348 368 /*********************************************************************** 349 369 350 Bulk copy of data from 'src'. Limit is adjusted by 'size' 351 bytes. 352 353 ***********************************************************************/ 354 355 protected void copy (void *src, uint size) 356 { 357 data[limit..limit+size] = src[0..size]; 358 limit += size; 359 } 360 361 /*********************************************************************** 362 363 Read a chunk of data from the buffer, loading from the 370 Read a slice of data from the buffer, loading from the 364 371 conduit as necessary. The specified number of bytes is 365 372 loaded into the buffer, and marked as having been read 366 373 when the 'eat' parameter is set true. When 'eat' is set 367 374 false, the read position is not adjusted. 375 376 Note that the slice cannot be larger than the size of 377 the buffer ~ use method get(void[]) instead where you 378 simply want the content copied, or use conduit.read() 379 to extract directly from an attached conduit. 368 380 369 381 Returns the corresponding buffer slice when successful, … … 403 415 404 416 /*********************************************************************** 405 417 406 418 Fill the provided array with content. We try to satisfy 407 419 the request from the buffer content, and read directly 408 from theconduit where more is required.420 from an attached conduit where more is required. 409 421 410 422 Returns true if the request was satisfied; false otherwise … … 434 446 the current thread forever, although usage of SocketConduit 435 447 will take advantage of the timeout facilities provided there. 448 449 Note that this is not intended to provide 'barrier' style 450 semantics for multi-threaded producer/consumer environments. 436 451 437 452 ***********************************************************************/ … … 479 494 /*********************************************************************** 480 495 481 Return a char[] slice of the buffer up to the limit of 482 valid content. 496 Append another buffer to this one, and flush to the 497 conduit as necessary. Returns a chaining reference if all 498 data was written; throws an IOException indicating eof or 499 eob if not. 500 501 This is often used in lieu of a Writer. 502 503 ***********************************************************************/ 504 505 IBuffer append (IBuffer other) 506 { 507 return append (other.toString); 508 } 509 510 /*********************************************************************** 511 512 Return a char[] slice of the buffer, from the current position 513 up to the limit of valid content. The content remains in the 514 buffer for future extraction. 483 515 484 516 ***********************************************************************/ … … 494 526 the associated conduit as necessary. 495 527 496 Can also reverse the read position by 'size' bytes. This may 497 be used to support lookahead-type operations. 528 Can also reverse the read position by 'size' bytes, when size 529 is negative. This may be used to support lookahead operations. 530 Note that a negative size will fail where there is not sufficient 531 content available in the buffer (can't skip beyond the beginning). 498 532 499 533 Returns true if successful, false otherwise. … … 715 749 /*********************************************************************** 716 750 717 make some room in the buffer 751 Make some room in the buffer. The requested space is simply 752 an indicator of how much is desired. A subclass may or may 753 not fulfill the request directly. 754 755 For example, the base-class simply performs a drain() on the 756 buffer. 718 757 719 758 ***********************************************************************/ … … 764 803 /*********************************************************************** 765 804 766 Reset 'position' and 'limit' to zero 805 Reset 'position' and 'limit' to zero. This effectively clears 806 all content from the buffer. 807 767 808 768 809 ***********************************************************************/ … … 793 834 /*********************************************************************** 794 835 795 Returns the limit of readable content within this buffer 836 Returns the limit of readable content within this buffer. 837 838 Each buffer has a capacity, a limit, and a position. The 839 capacity is the maximum content a buffer can contain, limit 840 represents the extent of valid content, and position marks 841 the current read location. 796 842 797 843 ***********************************************************************/ … … 804 850 /*********************************************************************** 805 851 806 Returns the total capacity of this buffer 852 Returns the maximum capacity of this buffer 853 854 Each buffer has a capacity, a limit, and a position. The 855 capacity is the maximum content a buffer can contain, limit 856 represents the extent of valid content, and position marks 857 the current read location. 807 858 808 859 ***********************************************************************/ … … 816 867 817 868 Returns the current read-position within this buffer 869 870 Each buffer has a capacity, a limit, and a position. The 871 capacity is the maximum content a buffer can contain, limit 872 represents the extent of valid content, and position marks 873 the current read location. 818 874 819 875 ***********************************************************************/ … … 855 911 this.conduit = conduit; 856 912 } 913 914 /*********************************************************************** 915 916 Return the entire backing array. Exposed for subclass usage 917 only 918 919 ***********************************************************************/ 920 921 protected void[] getContent () 922 { 923 return data; 924 } 925 926 /*********************************************************************** 927 928 Bulk copy of data from 'src'. The new content is made 929 available for reading. This is exposed for subclass use 930 only 931 932 ***********************************************************************/ 933 934 protected void copy (void *src, uint size) 935 { 936 data[limit..limit+size] = src[0..size]; 937 limit += size; 938 } 857 939 } trunk/mango/io/model/IBuffer.d
r853 r898 43 43 /******************************************************************************* 44 44 45 The basic premise behind this IO package is as follows: 46 47 1) the central concept is that of a buffer. The buffer acts 48 as a queue (line) where items are removed from the front 49 and new items are added to the back. Buffers are modeled 50 by this interface, and mango.io.Buffer exposes a concrete 51 implementation. 52 53 2) buffers can be written to directly, but a Reader and/or 54 Writer are typically used to read & write formatted data. 55 These readers & writers are bound to a specific buffer; 56 often the same buffer. It's also perfectly legitimate to 57 bind multiple writers to the same buffer; they will all 58 behave serially as one would expect. The same applies to 59 multiple readers on the same buffer. Readers and writers 60 support two styles of IO: put/get, and the C++ style << 61 and >> operators. All such operations can be chained. 62 63 3) Any class can be made compatable with the reader/writer 64 framework by implementing the IReadable and/or IWritable 65 interfaces. Each of these specify just a single method. 66 67 4) Buffers may also be tokenized. This is handy when one is 68 dealing with text input, and/or the content suits a more 69 fluid format than most typical readers & writers support. 70 Tokens are mapped directly onto buffer content, so there 71 is only minor overhead in using them. Tokens can be read 72 and written by reader/writers also, using a more relaxed 73 set of rules than those applied to integral IO. 74 75 5) buffers are sometimes memory-only, in which case there 76 is nothing left to do when a reader (or tokenizer) hits 77 end of buffer conditions. Other buffers are themselves 78 bound to a Conduit. When this is the case, a reader will 79 eventually cause the buffer to reload via its associated 80 conduit. Previous buffer content will thus be lost. The 81 same concept is applied to writers, whereby they flush 82 the content of a full buffer to a bound conduit before 83 continuing. 84 85 6) conduits provide virtualized access to external content, 86 and represent things like files or Internet connections. 87 They are just a different kind of stream. Conduits are 88 modelled by mango.io.model.IConduit, and implemented via 89 classes FileConduit and SocketConduit. Additional kinds 90 of conduit are easy to construct: one either subclasses 91 mango.io.Conduit, or implements mango.io.model.IConduit. A 92 conduit reads and writes from/to a buffer in big chunks 93 (typically the entire buffer). 94 45 the central concept is that of a buffer. The buffer acts 46 as a queue (line) where items are removed from the front 47 and new items are added to the back. Buffers are modeled 48 by this interface, and mango.io.Buffer exposes a concrete 49 implementation. 50 51 buffers can be written to directly, but a Reader and/or 52 Writer are typically used to read & write formatted data. 53 These readers & writers are bound to a specific buffer; 54 often the same buffer. It's also perfectly legitimate to 55 bind multiple writers to the same buffer; they will all 56 behave serially as one would expect. The same applies to 57 multiple readers on the same buffer. Readers and writers 58 support two styles of IO: put/get, and the C++ style << 59 and >> operators. All such operations can be chained. 60 61 Any class can be made compatable with the reader/writer 62 framework by implementing the IReadable and/or IWritable 63 interfaces. Each of these specify just a single method. 64 65 Buffers may also be tokenized. This is handy when one is 66 dealing with text input, and/or the content suits a more 67 fluid format than most typical readers & writers support. 68 Tokens are mapped directly onto buffer content, so there 69 is only minor overhead in using them. Tokens can be read 70 and written by reader/writers also, using a more relaxed 71 set of rules than those applied to integral IO. 72 73 buffers are sometimes memory-only, in which case there 74 is nothing left to do when a reader (or tokenizer) hits 75 end of buffer conditions. Other buffers are themselves 76 bound to a Conduit. When this is the case, a reader will 77 eventually cause the buffer to reload via its associated 78 conduit. Previous buffer content will thus be lost. The 79 same concept is applied to writers, whereby they flush 80 the content of a full buffer to a bound conduit before 81 continuing. 82 83 conduits provide virtualized access to external content, 84 and represent things like files or Internet connections. 85 They are just a different kind of stream. Conduits are 86 modelled by mango.io.model.IConduit, and implemented via 87 classes FileConduit and SocketConduit. Additional kinds 88 of conduit are easy to construct: one either subclasses 89 mango.io.Conduit, or implements mango.io.model.IConduit. A 90 conduit reads and writes from/to a buffer in big chunks 91 (typically the entire buffer). 92 95 93 *******************************************************************************/ 96 94 97 abstract class IBuffer // could be an interface, but that causes poor codegen95 abstract class IBuffer /// could be an interface, but that causes poor codegen 98 96 { 99 97 typedef uint delegate (void* dst, uint count, uint type) Converter; … … 146 144 /*********************************************************************** 147 145 148 Writean array of data into this buffer, and flush to the146 Append an array of data into this buffer, and flush to the 149 147 conduit as necessary. Returns a chaining reference if all 150 148 data was written; throws an IOException indicating eof or … … 156 154 157 155 abstract IBuffer append (void[] content); 156 157 /*********************************************************************** 158 159 Append another buffer to this one, and flush to the 160 conduit as necessary. Returns a chaining reference if all 161 data was written; throws an IOException indicating eof or 162 eob if not. 163 164 This is often used in lieu of a Writer. 165 166 ***********************************************************************/ 167 168 IBuffer append (IBuffer other); 158 169 159 170 /***********************************************************************
