1 module hunt.stream.StringWriter; 2 3 import hunt.Exceptions; 4 import hunt.util.Common; 5 import hunt.stream.Writer; 6 7 import std.algorithm; 8 import std.array; 9 import std.exception; 10 import std.conv; 11 import std.string; 12 13 14 15 /** 16 * A character stream that collects its output in a string buffer, which can 17 * then be used to construct a string. 18 * <p> 19 * Closing a {@code StringWriter} has no effect. The methods in this class 20 * can be called after the stream has been closed without generating an 21 * {@code IOException}. 22 * 23 * @author Mark Reinhold 24 */ 25 26 class StringWriter : Writer { 27 28 private Appender!(string) buf; 29 30 /** 31 * Create a new string writer using the default initial string-buffer 32 * size. 33 */ 34 this() { 35 buf.reserve(1024); 36 lock = this; 37 } 38 39 /** 40 * Create a new string writer using the specified initial string-buffer 41 * size. 42 * 43 * @param initialSize 44 * The number of {@code char} values that will fit into this buffer 45 * before it is automatically expanded 46 * 47 * @throws IllegalArgumentException 48 * If {@code initialSize} is negative 49 */ 50 this(int initialSize) { 51 if (initialSize < 0) { 52 throw new IllegalArgumentException("Negative buffer size"); 53 } 54 buf.reserve(initialSize); 55 lock = this; 56 } 57 58 /** 59 * Write a single character. 60 */ 61 override void write(int c) { 62 buf.put(to!string(cast(char)c)); 63 } 64 65 /** 66 * Write a portion of an array of characters. 67 * 68 * @param cbuf Array of characters 69 * @param off Offset from which to start writing characters 70 * @param len Number of characters to write 71 * 72 * @throws IndexOutOfBoundsException 73 * If {@code off} is negative, or {@code len} is negative, 74 * or {@code off + len} is negative or greater than the length 75 * of the given array 76 */ 77 override void write(byte[] cbuf, int off, int len) { 78 if ((off < 0) || (off > cbuf.length) || (len < 0) || 79 ((off + len) > cbuf.length) || ((off + len) < 0)) { 80 throw new IndexOutOfBoundsException(); 81 } else if (len == 0) { 82 return; 83 } 84 buf.put(cast(string)cbuf[off .. off+ len]); 85 } 86 87 /** 88 * Write a string. 89 */ 90 override void write(string str) { 91 buf.put(str); 92 } 93 94 /** 95 * Write a portion of a string. 96 * 97 * @param str string to be written 98 * @param off Offset from which to start writing characters 99 * @param len Number of characters to write 100 * 101 * @throws IndexOutOfBoundsException 102 * If {@code off} is negative, or {@code len} is negative, 103 * or {@code off + len} is negative or greater than the length 104 * of the given string 105 */ 106 override void write(string str, int off, int len) { 107 buf.put(str[off .. off+ len]); 108 } 109 110 /** 111 * Appends the specified character to this writer. 112 * 113 * <p> An invocation of this method of the form {@code out.append(c)} 114 * behaves in exactly the same way as the invocation 115 * 116 * <pre> 117 * out.write(c) </pre> 118 * 119 * @param c 120 * The 16-bit character to append 121 * 122 * @return This writer 123 * 124 */ 125 override StringWriter append(char c) { 126 write(c); 127 return this; 128 } 129 130 /** 131 * Return the buffer's current value as a string. 132 */ 133 override string toString() { 134 return buf.data; 135 } 136 137 /** 138 * Return the string buffer itself. 139 * 140 * @return StringBuffer holding the current buffer value. 141 */ 142 ref Appender!(string) getBuffer() { 143 return buf; 144 } 145 146 /** 147 * Flush the stream. 148 */ 149 override void flush() { 150 } 151 152 /** 153 * Closing a {@code StringWriter} has no effect. The methods in this 154 * class can be called after the stream has been closed without generating 155 * an {@code IOException}. 156 */ 157 override void close() { 158 } 159 160 }