1 /*******************************************************************************
2 3 Copyright:
4 Copyright (c) 2004 Kris Bell.
5 Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
6 All rights reserved.
7 8 License:
9 Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
10 See LICENSE_TANGO.txt for details.
11 12 Version:
13 Mar 2004: Initial release$(BR)
14 Dec 2006: Outback release
15 16 Authors: Kris
17 18 *******************************************************************************/19 20 moduleocean.io.device.Array;
21 22 importocean.meta.types.Qualifiers;
23 24 importocean.core.Verify;
25 26 importocean.core.ExceptionDefinitions;
27 28 importocean.io.device.Conduit;
29 30 /******************************************************************************
31 32 ******************************************************************************/33 34 extern (C)
35 {
36 protectedvoid * memcpy (void *dst, const(void)* src, size_t);
37 }
38 39 /*******************************************************************************
40 41 Array manipulation typically involves appending, as in the
42 following example:
43 ---
44 // create a small buffer
45 auto buf = new Array (256);
46 47 auto foo = "to write some D";
48 49 // append some text directly to it
50 buf.append ("now is the time for all good men ").append(foo);
51 ---
52 53 Alternatively, one might use a formatter to append content:
54 ---
55 auto output = new TextOutput (new Array(256));
56 output.format ("now is the time for {} good men {}", 3, foo);
57 ---
58 59 A slice() method returns all valid content within the array.
60 61 *******************************************************************************/62 63 classArray : Conduit, InputBuffer, OutputBuffer, Conduit.Seek64 {
65 privatevoid[] data; // the raw data buffer66 privatesize_tindex; // current read position67 privatesize_textent; // limit of valid content68 privatesize_tdimension; // maximum extent of content69 privatesize_texpansion; // for growing instances70 71 privatestaticistringoverflow = "output buffer is full";
72 privatestaticistringunderflow = "input buffer is empty";
73 privatestaticistringeofRead = "end-of-flow while reading";
74 privatestaticistringeofWrite = "end-of-flow while writing";
75 76 /***********************************************************************
77 78 Ensure the buffer remains valid between method calls.
79 80 ***********************************************************************/81 82 invariant()
83 {
84 assert (index <= extent);
85 assert (extent <= dimension);
86 }
87 88 /***********************************************************************
89 90 Construct a buffer.
91 92 Params:
93 capacity = The number of bytes to make available.
94 growing = Chunk size of a growable instance, or zero
95 to prohibit expansion.
96 97 Remarks:
98 Construct a Buffer with the specified number of bytes
99 and expansion policy.
100 101 ***********************************************************************/102 103 this (size_tcapacity, size_tgrowing = 0)
104 {
105 assign (newubyte[capacity], 0);
106 expansion = growing;
107 }
108 109 /***********************************************************************
110 111 Construct a buffer.
112 113 Params:
114 data = The backing array to buffer within.
115 116 Remarks:
117 Prime a buffer with an application-supplied array. All content
118 is considered valid for reading, and thus there is no writable
119 space initially available.
120 121 ***********************************************************************/122 123 this (void[] data)
124 {
125 assign (data, data.length);
126 }
127 128 /***********************************************************************
129 130 Construct a buffer.
131 132 Params:
133 data = The backing array to buffer within.
134 readable = The number of bytes initially made
135 readable.
136 137 Remarks:
138 Prime buffer with an application-supplied array, and
139 indicate how much readable data is already there. A
140 write operation will begin writing immediately after
141 the existing readable content.
142 143 This is commonly used to attach a Buffer instance to
144 a local array.
145 146 ***********************************************************************/147 148 this (void[] data, size_treadable)
149 {
150 assign (data, readable);
151 }
152 153 /***********************************************************************
154 155 Return the name of this conduit.
156 157 ***********************************************************************/158 159 finaloverrideistringtoString ()
160 {
161 return"<array>";
162 }
163 164 /***********************************************************************
165 166 Transfer content into the provided dst.
167 168 Params:
169 dst = Destination of the content.
170 171 Returns:
172 Return the number of bytes read, which may be less than
173 dst.length. Eof is returned when no further content is
174 available.
175 176 Remarks:
177 Populates the provided array with content. We try to
178 satisfy the request from the buffer content, and read
179 directly from an attached conduit when the buffer is
180 empty.
181 182 ***********************************************************************/183 184 finaloverridesize_tread (void[] dst)
185 {
186 autocontent = readable;
187 if (content)
188 {
189 if (content >= dst.length)
190 content = dst.length;
191 192 // transfer buffer content193 dst [0 .. content] = data [index .. index + content];
194 index += content;
195 }
196 else197 content = IConduit.Eof;
198 returncontent;
199 }
200 201 /***********************************************************************
202 203 Emulate OutputStream.write().
204 205 Params:
206 src = The content to write.
207 208 Returns:
209 Return the number of bytes written, which may be less than
210 provided (conceptually). Returns Eof when the buffer becomes
211 full.
212 213 Remarks:
214 Appends src content to the buffer, expanding as required if
215 configured to do so (via the ctor).
216 217 ***********************************************************************/218 219 finaloverridesize_twrite (const(void)[] src)
220 {
221 autolen = src.length;
222 if (len)
223 {
224 if (len > writable)
225 if (expand(len) < len)
226 returnEof;
227 228 // content may overlap ...229 memcpy (&data[extent], src.ptr, len);
230 extent += len;
231 }
232 returnlen;
233 }
234 235 /***********************************************************************
236 237 Return a preferred size for buffering conduit I/O.
238 239 ***********************************************************************/240 241 finaloverridesize_tbufferSize ()
242 {
243 returndata.length;
244 }
245 246 /***********************************************************************
247 248 Release external resources.
249 250 ***********************************************************************/251 252 overridevoiddetach ()
253 {
254 }
255 256 /***********************************************************************
257 258 Seek within the constraints of assigned content.
259 260 ***********************************************************************/261 262 overridelongseek (longoffset, Anchoranchor = Anchor.Begin)
263 {
264 if (offset > cast(long) limit)
265 offset = limit;
266 267 switch (anchor)
268 {
269 caseAnchor.End:
270 index = cast(size_t) (limit - offset);
271 break;
272 273 caseAnchor.Begin:
274 index = cast(size_t) offset;
275 break;
276 277 caseAnchor.Current:
278 longo = cast(size_t) (index + offset);
279 if (o < 0)
280 o = 0;
281 if (o > cast(long) limit)
282 o = limit;
283 index = cast(size_t) o;
284 gotodefault;
285 default:
286 break;
287 }
288 returnindex;
289 }
290 291 /***********************************************************************
292 293 Reset the buffer content.
294 295 Params:
296 data = The backing array to buffer within. All content
297 is considered valid.
298 299 Returns:
300 The buffer instance.
301 302 Remarks:
303 Set the backing array with all content readable.
304 305 ***********************************************************************/306 307 Arrayassign (void[] data)
308 {
309 returnassign (data, data.length);
310 }
311 312 /***********************************************************************
313 314 Reset the buffer content
315 316 Params:
317 data = The backing array to buffer within.
318 readable = The number of bytes within data considered
319 valid.
320 321 Returns:
322 The buffer instance.
323 324 Remarks:
325 Set the backing array with some content readable. Use clear()
326 to reset the content (make it all writable).
327 328 ***********************************************************************/329 330 Arrayassign (void[] data, size_treadable)
331 {
332 this.data = data;
333 this.extent = readable;
334 this.dimension = data.length;
335 336 // reset to start of input337 this.expansion = 0;
338 this.index = 0;
339 returnthis;
340 }
341 342 /***********************************************************************
343 344 Access buffer content.
345 346 Remarks:
347 Return the entire backing array.
348 349 ***********************************************************************/350 351 finalvoid[] assign ()
352 {
353 returndata;
354 }
355 356 /***********************************************************************
357 358 Return a void[] read of the buffer from start to end, where
359 end is exclusive.
360 361 ***********************************************************************/362 363 finalvoid[] opSlice (size_tstart, size_tend)
364 {
365 verify(start <= extent && end <= extent && start <= end);
366 returndata [start .. end];
367 }
368 369 /***********************************************************************
370 371 Retrieve all readable content.
372 373 Returns:
374 A void[] read of the buffer.
375 376 Remarks:
377 Return a void[] read of the buffer, from the current position
378 up to the limit of valid content. The content remains in the
379 buffer for future extraction.
380 381 ***********************************************************************/382 383 finalvoid[] slice ()
384 {
385 returndata [index .. extent];
386 }
387 388 /***********************************************************************
389 390 Access buffer content.
391 392 Params:
393 size = Number of bytes to access.
394 eat = Whether to consume the content or not.
395 396 Returns:
397 The corresponding buffer slice when successful, or
398 null if there's not enough data available (Eof; Eob).
399 400 Remarks:
401 Slices readable data. The specified number of bytes is
402 readd from the buffer, and marked as having been read
403 when the 'eat' parameter is set true. When 'eat' is set
404 false, the read position is not adjusted.
405 406 Note that the slice cannot be larger than the size of
407 the buffer ~ use method read(void[]) instead where you
408 simply want the content copied.
409 410 Note also that the slice should be .dup'd if you wish to
411 retain it.
412 413 Examples:
414 ---
415 // create a buffer with some content
416 auto buffer = new Buffer ("hello world");
417 418 // consume everything unread
419 auto slice = buffer.slice (buffer.readable);
420 ---
421 422 ***********************************************************************/423 424 finalvoid[] slice (size_tsize, booleat = true)
425 {
426 if (size > readable)
427 error (underflow);
428 429 autoi = index;
430 if (eat)
431 index += size;
432 returndata [i .. i + size];
433 }
434 435 /***********************************************************************
436 437 Append content.
438 439 Params:
440 src = The content to _append.
441 442 Returns:
443 A chaining reference if all content was written.
444 Throws an IOException indicating eof or eob if not.
445 446 Remarks:
447 Append an array to this buffer.
448 449 ***********************************************************************/450 451 finalArrayappend (const(void)[] src)
452 {
453 if (write(src) isEof)
454 error (overflow);
455 returnthis;
456 }
457 458 /***********************************************************************
459 460 Iterator support.
461 462 Params:
463 scan = The delagate to invoke with the current content
464 465 Returns:
466 Returns true if a token was isolated, false otherwise.
467 468 Remarks:
469 Upon success, the delegate should return the byte-based
470 index of the consumed pattern (tail end of it). Failure
471 to match a pattern should be indicated by returning an
472 IConduit.Eof.
473 474 Note that additional iterator and/or reader instances
475 will operate in lockstep when bound to a common buffer.
476 477 ***********************************************************************/478 479 finalboolnext (scopesize_tdelegate (const(void)[]) scan)
480 {
481 returnreader (scan) != IConduit.Eof;
482 }
483 484 /***********************************************************************
485 486 Available content.
487 488 Remarks:
489 Return count of _readable bytes remaining in buffer. This is
490 calculated simply as limit() - position().
491 492 ***********************************************************************/493 494 finalsize_treadable ()
495 {
496 returnextent - index;
497 }
498 499 /***********************************************************************
500 501 Available space.
502 503 Remarks:
504 Return count of _writable bytes available in buffer. This is
505 calculated simply as capacity() - limit().
506 507 ***********************************************************************/508 509 finalsize_twritable ()
510 {
511 returndimension - extent;
512 }
513 514 /***********************************************************************
515 516 Access buffer limit.
517 518 Returns:
519 Returns the limit of readable content within this buffer.
520 521 Remarks:
522 Each buffer has a capacity, a limit, and a position. The
523 capacity is the maximum content a buffer can contain, limit
524 represents the extent of valid content, and position marks
525 the current read location.
526 527 ***********************************************************************/528 529 finalsize_tlimit ()
530 {
531 returnextent;
532 }
533 534 /***********************************************************************
535 536 Access buffer capacity.
537 538 Returns:
539 Returns the maximum capacity of this buffer.
540 541 Remarks:
542 Each buffer has a capacity, a limit, and a position. The
543 capacity is the maximum content a buffer can contain, limit
544 represents the extent of valid content, and position marks
545 the current read location.
546 547 ***********************************************************************/548 549 finalsize_tcapacity ()
550 {
551 returndimension;
552 }
553 554 /***********************************************************************
555 556 Access buffer read position.
557 558 Returns:
559 Returns the current read-position within this buffer
560 561 Remarks:
562 Each buffer has a capacity, a limit, and a position. The
563 capacity is the maximum content a buffer can contain, limit
564 represents the extent of valid content, and position marks
565 the current read location.
566 567 ***********************************************************************/568 569 finalsize_tposition ()
570 {
571 returnindex;
572 }
573 574 /***********************************************************************
575 576 Clear array content.
577 578 Remarks:
579 Reset 'position' and 'limit' to zero. This effectively
580 clears all content from the array.
581 582 ***********************************************************************/583 584 finalArrayclear ()
585 {
586 index = extent = 0;
587 returnthis;
588 }
589 590 /***********************************************************************
591 592 Emit/purge buffered content.
593 594 ***********************************************************************/595 596 finaloverrideArrayflush ()
597 {
598 returnthis;
599 }
600 601 /***********************************************************************
602 603 Write into this buffer.
604 605 Params:
606 dg = The callback to provide buffer access to.
607 608 Returns:
609 Returns whatever the delegate returns.
610 611 Remarks:
612 Exposes the raw data buffer at the current _write position,
613 The delegate is provided with a void[] representing space
614 available within the buffer at the current _write position.
615 616 The delegate should return the appropriate number of bytes
617 if it writes valid content, or IConduit.Eof on error.
618 619 ***********************************************************************/620 621 finalsize_twriter (scopesize_tdelegate (void[]) dg)
622 {
623 autocount = dg (data [extent..dimension]);
624 625 if (count != IConduit.Eof)
626 {
627 extent += count;
628 verify(extent <= dimension);
629 }
630 returncount;
631 }
632 633 /***********************************************************************
634 635 Read directly from this buffer.
636 637 Params:
638 dg = Callback to provide buffer access to.
639 640 Returns:
641 Returns whatever the delegate returns.
642 643 Remarks:
644 Exposes the raw data buffer at the current _read position. The
645 delegate is provided with a void[] representing the available
646 data, and should return zero to leave the current _read position
647 intact.
648 649 If the delegate consumes data, it should return the number of
650 bytes consumed; or IConduit.Eof to indicate an error.
651 652 ***********************************************************************/653 654 finalsize_treader (scopesize_tdelegate (const(void)[]) dg)
655 {
656 autocount = dg (data [index..extent]);
657 658 if (count != IConduit.Eof)
659 {
660 index += count;
661 verify(index <= extent);
662 }
663 returncount;
664 }
665 666 /***********************************************************************
667 668 Expand existing buffer space.
669 670 Returns:
671 Available space, without any expansion.
672 673 Remarks:
674 Make some additional room in the buffer, of at least the
675 given size. Should not be public in order to avoid issues
676 with non-growable subclasses.
677 678 ***********************************************************************/679 680 privatefinalsize_texpand (size_tsize)
681 {
682 if (expansion)
683 {
684 if (size < expansion)
685 size = expansion;
686 dimension += size;
687 data.length = dimension;
688 }
689 returnwritable;
690 }
691 692 /***********************************************************************
693 694 Cast to a target type without invoking the wrath of the
695 runtime checks for misalignment. Instead, we truncate the
696 array length.
697 698 ***********************************************************************/699 700 privatestaticT[] convert(T)(void[] x)
701 {
702 return (cast(T*) x.ptr) [0 .. (x.length / T.sizeof)];
703 }
704 }
705 706 707 /******************************************************************************
708 709 ******************************************************************************/710 711 debug (Array)
712 {
713 importocean.io.Stdout;
714 715 voidmain()
716 {
717 autob = newArray(6, 10);
718 b.seek (0);
719 b.write ("fubar");
720 721 Stdout.formatln ("extent {}, pos {}, read {}, bufsize {}",
722 b.limit, b.position, cast(char[]) b.slice, b.bufferSize);
723 724 b.write ("fubar");
725 Stdout.formatln ("extent {}, pos {}, read {}, bufsize {}",
726 b.limit, b.position, cast(char[]) b.slice, b.bufferSize);
727 }
728 }