KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derbyTesting > functionTests > util > streams > LoopingAlphabetStream


1 /*
2
3    Derby - Class org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetStream
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derbyTesting.functionTests.util.streams;
23
24 import java.io.InputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26
27 /**
28  * A stream returning a cycle of the 26 lowercase letters of the modern Latin
29  * alphabet.
30  */

31 public class LoopingAlphabetStream
32     extends InputStream JavaDoc {
33
34     /**
35      * Maximum size of buffer.
36      * Balance between size and memory usage.
37      */

38     private static final int MAX_BUF_SIZE = 32*1024;
39     private static final byte SPACE = (byte)' ';
40
41     /** Length of the stream. */
42     private final long length;
43     private final int trailingBlanks;
44     /** Remaining bytes in the stream. */
45     private long remainingBlanks;
46     private long remainingNonBlanks;
47     private byte[] buffer = new byte[0];
48     private final ByteAlphabet alphabet;
49
50     /**
51      * Create a looping modern latin alphabet stream of the specified length.
52      *
53      * @param length the number of characters (and also the number of bytes)
54      */

55     public LoopingAlphabetStream(long length) {
56         this(length, 0);
57     }
58
59     public LoopingAlphabetStream(long length, int trailingBlanks) {
60         this.length = length;
61         this.trailingBlanks = trailingBlanks;
62         this.remainingNonBlanks = length - trailingBlanks;
63         this.remainingBlanks = trailingBlanks;
64         this.alphabet = ByteAlphabet.modernLatinLowercase();
65         fillBuffer(alphabet.byteCount());
66     }
67
68     /**
69      * Create a looping alphabet of the specified type and length.
70      *
71      * @param length the number of bytes in the stream
72      * @param alphabet the alphabet to loop over
73      */

74     public LoopingAlphabetStream(long length, ByteAlphabet alphabet) {
75         this(length, alphabet, 0);
76     }
77
78     public LoopingAlphabetStream(long length,
79                                  ByteAlphabet alphabet,
80                                  int trailingBlanks) {
81         this.length = length;
82         this.trailingBlanks = trailingBlanks;
83         this.remainingNonBlanks = length - trailingBlanks;
84         this.remainingBlanks = trailingBlanks;
85         this.alphabet = alphabet;
86         fillBuffer(alphabet.byteCount());
87     }
88
89     public int read() {
90         if (remainingBlanks <= 0 && remainingNonBlanks <= 0) {
91             return -1;
92         }
93         if (remainingNonBlanks <= 0) {
94             remainingBlanks--;
95             return SPACE;
96         }
97         remainingNonBlanks--;
98         return alphabet.nextByte();
99     }
100
101     public int read(byte[] buf, int off, int length) {
102         if (remainingBlanks <= 0 && remainingNonBlanks <= 0) {
103             return -1;
104         }
105         // We can only read as many bytes as there are in the stream.
106
int nonBlankLength = Math.min((int)remainingNonBlanks, length);
107         fillBuffer(nonBlankLength);
108         int read = 0;
109         // Find position of next letter in the buffer.
110
int bOff = alphabet.nextByteToRead(0);
111         if (nonBlankLength <= (buffer.length - bOff)) {
112             System.arraycopy(buffer, bOff, buf, off, nonBlankLength);
113             remainingNonBlanks -= nonBlankLength;
114             read = nonBlankLength;
115             alphabet.nextByteToRead(nonBlankLength);
116         } else {
117             // Must read several times from the buffer.
118
int toRead = 0;
119             while (remainingNonBlanks > 0 && read < nonBlankLength) {
120                 bOff = alphabet.nextByteToRead(toRead);
121                 toRead = Math.min(buffer.length - bOff, nonBlankLength - read);
122                 System.arraycopy(buffer, bOff, buf, off + read, toRead);
123                 remainingNonBlanks -= toRead;
124                 read += toRead;
125             }
126             bOff = alphabet.nextByteToRead(toRead);
127         }
128         if (read < length && remainingBlanks > 0) {
129             read += fillBlanks(buf, off + read, length - read);
130         }
131         return read;
132     }
133
134     /**
135      * Reset the stream.
136      */

137     public void reset() {
138         remainingNonBlanks = length - trailingBlanks;
139         remainingBlanks = trailingBlanks;
140         alphabet.reset();
141     }
142
143     /**
144      * Return remaining bytes in the stream.
145      */

146     public int available() {
147         return (int)(remainingNonBlanks + remainingBlanks);
148     }
149
150     /**
151      * Fill internal buffer of bytes (from character sequence).
152      *
153      * @param bufSize the wanted size, might be ignored if too big
154      */

155     private void fillBuffer(int bufSize) {
156         if (bufSize > MAX_BUF_SIZE) {
157             bufSize = MAX_BUF_SIZE;
158         }
159         if (bufSize <= buffer.length) {
160             return;
161         }
162         int curOff = alphabet.nextByteToRead(0);
163         // First letter in buffer is always the first letter in the alphabet.
164
alphabet.reset();
165         buffer = new byte[bufSize];
166         for (int i=0; i < bufSize; i++) {
167             buffer[i] = alphabet.nextByte();
168         }
169         // Must reset internal state of the alphabet, as we have not yet
170
// delivered any bytes.
171
alphabet.reset();
172         alphabet.nextByteToRead(curOff);
173     }
174
175     private int fillBlanks(byte[] buf, int off, int length) {
176         int i=0;
177         for (; i < length; i++) {
178             if (remainingBlanks > 0) {
179                 buf[off+i] = SPACE;
180                 remainingBlanks--;
181             } else {
182                 break;
183             }
184         }
185         return i;
186     }
187 } // End class LoopingAlphabetStream
188
Popular Tags