Codebase list libbytelist-java / 7aa2bb2
Add lot o javadocs and some assertions Thomas E. Enebo 14 years ago
1 changed file(s) with 641 addition(s) and 139 deletion(s). Raw diff Collapse all Expand all
3030 ***** END LICENSE BLOCK *****/
3131 package org.jruby.util;
3232
33 import java.io.EOFException;
3433 import java.io.IOException;
3534 import java.io.InputStream;
3635 import java.io.Serializable;
37 import java.io.UnsupportedEncodingException;
3836 import java.nio.ByteBuffer;
3937 import java.nio.CharBuffer;
4038 import java.nio.charset.Charset;
4644 import org.jcodings.specific.ASCIIEncoding;
4745
4846 /**
49 *
50 * @author headius
47 * ByteList is simple a collection of bytes in the same way a Java String is a collection
48 * of characters. However, it's API resembles StringBuffer/StringBuilder more than String
49 * because it is a mutable object.
5150 */
5251 @SuppressWarnings("deprecation")
5352 public final class ByteList implements Comparable, CharSequence, Serializable {
5857
5958 @Deprecated
6059 public byte[] bytes;
60
6161 @Deprecated
6262 public int begin;
63
6364 @Deprecated
6465 public int realSize;
66
6567 @Deprecated
6668 public Encoding encoding = ASCIIEncoding.INSTANCE;
69
6770 int hash;
71
6872 String stringValue;
6973
7074 private static final int DEFAULT_SIZE = 4;
7175
72 /** Creates a new instance of ByteList */
76 /**
77 * Creates a new instance of ByteList
78 */
7379 public ByteList() {
7480 this(DEFAULT_SIZE);
7581 }
7682
83 /**
84 * Creates a new instance of Bytelist with a pre-allocated size. If you know the size ahead
85 * of time this saves additional array allocations to grow the bytelist to the proper size.
86 *
87 * @param size to preallocate the bytelist to
88 */
7789 public ByteList(int size) {
7890 bytes = new byte[size];
7991 realSize = 0;
8092 }
8193
94 /**
95 * Create a new instance of ByteList with the bytes supplied using the specified encoding.
96 *
97 * Important: bytes is used as the initial backing store for the bytelist. Over time as the
98 * bytelist is mutated this backing store may be replaced with a new one to hold the additional
99 * bytes. If you pass in bytes and then modify the contents of the original bytes, then those
100 * changes will get reflected.
101 *
102 * @param bytes to use
103 * @param encoding
104 */
105 // TODO: Deprecate and replace with a static method which implies the caveats of this constructor.
82106 public ByteList(byte[] bytes, Encoding encoding) {
83107 this.bytes = bytes;
84108 this.realSize = bytes.length;
85109 this.encoding = encoding;
86110 }
87111
112 /**
113 * Create a new instance of ByteList with the contents of wrap. This constructor will make
114 * a copy of bytes passed
115 *
116 * @param wrap the initial bytes for this ByteList
117 */
88118 public ByteList(byte[] wrap) {
89 this (wrap, true);
90 }
91
119 this(wrap, true);
120 }
121
122 /**
123 * Create a new instance of ByteList with the contents of wrap. If copy is true then it will
124 * array copy the contents. Otherwise it will use the byte array passed in as its initial
125 * backing store.
126 *
127 * @param wrap the initial bytes for this ByteList
128 * @param copy whether to arraycopy wrap for the backing store or not
129 */
92130 public ByteList(byte[] wrap, boolean copy) {
93131 assert wrap != null;
94132 if (copy) {
99137 realSize = wrap.length;
100138 }
101139
140 /**
141 * Create a new instance of byte list with the same contents as the passed in ByteList wrap.
142 * Note that this does array copy the data for the new objects initial backing store.
143 *
144 * @param wrap is contents for new ByteList
145 */
102146 public ByteList(ByteList wrap) {
103147 this(wrap.bytes, wrap.begin, wrap.realSize);
104148 }
105149
150 /**
151 * Create a new instance of ByteList with the same contents as the passed in ByteList wrap.
152 * The copy parameter gives you control over whether you want this new ByteList to share
153 * the same byte array for its backing store.
154 *
155 * ****IMPORTANT NOTES*****
156 * copy is currently ignored and always assumed false. This constructor should just go away
157 * so it has been marked as deprecated.
158 *
159 * @param wrap
160 * @param copy
161 *
162 * Deprecated to coincide with JRuby 1.5 (not used by anything we can find luckily)
163 */
164 @Deprecated
106165 public ByteList(ByteList wrap, boolean copy) {
107166 this(wrap.bytes, wrap.begin, wrap.realSize, false);
108167 }
109168
169 /**
170 * Create a new instance of ByteList using wrap as a backing store where index is the first
171 * index in the byte array where the data starts and len indicates how long the data portion
172 * of the bytelist is. wrap will be array copied in this constructor.
173 *
174 * @param wrap the bytes to use
175 * @param index where in the bytes the data starts
176 * @param len how long the data is in the wrap array
177 */
110178 public ByteList(byte[] wrap, int index, int len) {
111 this(wrap,index,len,true);
112 }
113
179 this(wrap, index, len, true);
180 }
181
182 /**
183 * Create a new instance of ByteList using wrap as a backing store where index is the first
184 * index in the byte array where the data starts and len indicates how long the data portion
185 * of the bytelist is. wrap will be array copied if copy is true OR if index != 0.
186 *
187 * @param wrap the bytes to use
188 * @param index where in the bytes the data starts
189 * @param len how long the data is in the wrap array
190 * @param copy if true array copy wrap. otherwise use as backing store
191 */
192 // FIXME: Fix the index != 0 not honoring copy and separate out into a different caller. JRuby.next would be the right time for this.
114193 public ByteList(byte[] wrap, int index, int len, boolean copy) {
115 assert wrap != null;
194 assert wrap != null : "'wrap' must not be null";
195 assert index >= 0 && index <= wrap.length : "'index' is not without bounds of 'wrap' array";
196 assert wrap.length >= index + len : "'index' + 'len' is longer than the 'wrap' array";
197
116198 if (copy || index != 0) {
117199 bytes = new byte[len];
118200 System.arraycopy(wrap, index, bytes, 0, len);
122204 realSize = len;
123205 }
124206
207 /**
208 * Create a new instance of ByteList using wrap as a backing store where index is the first
209 * index in the byte array where the data starts and len indicates how long the data portion
210 * of the bytelist is. wrap's byte array will be array copied for initial backing store.
211 *
212 * @param wrap the bytes to use
213 * @param index where in the bytes the data starts
214 * @param len how long the data is in the wrap array
215 */
125216 public ByteList(ByteList wrap, int index, int len) {
126217 this(wrap.bytes, wrap.begin + index, len);
127218 }
128219
129 private ByteList(boolean flag) {
130 }
131
220 /**
221 * Delete len bytes from start index. This does no bullet-proofing so it is your
222 * responsibility to ensure you do not run off the backing store array.
223 *
224 * @param start index to delete from
225 * @param len number of bytes to delete
226 */
132227 public void delete(int start, int len) {
133 realSize-=len;
134 System.arraycopy(bytes,start+len,bytes,start,realSize);
135 }
136
228 assert start >= begin && start < realSize : "'start' is at invalid index";
229 assert len >= 0 : "'len' must be positive";
230 assert start + len <= begin + realSize : "too many bytes requested";
231
232 realSize -= len;
233
234 System.arraycopy(bytes, start + len, bytes, start, realSize);
235 }
236
237 /**
238 * Append the byte b up to len times onto the end of the current ByteList.
239 *
240 * @param b is byte to be appended
241 * @param len is number of times to repeat the append
242 */
243 // FIXME: Innefficient impl since we know the len up front.
244 public void fill(int b, int len) {
245 for ( ; --len >= 0; ) {
246 append(b);
247 }
248 }
249
250 /**
251 * @see Object#clone()
252 */
253 @Override
254 public Object clone() {
255 return dup();
256 }
257
258 /**
259 * creates a duplicate of this bytelist but only in the case of a stringValue and its resulting
260 * hash value. No other elements are duplicated.
261 */
262 public ByteList dup() {
263 ByteList dup = dup(realSize);
264 dup.hash = hash;
265 dup.stringValue = stringValue;
266 return dup;
267 }
268
269 /**
270 * Create a new ByteList but do not array copy the byte backing store.
271 *
272 * @return a new ByteList with same backing store
273 */
274 public ByteList shallowDup() {
275 ByteList dup = new ByteList(bytes, false);
276 dup.realSize = realSize;
277 dup.begin = begin;
278 dup.encoding = encoding;
279 dup.hash = hash;
280 dup.stringValue = stringValue;
281 return dup;
282 }
283
284 /**
285 * @param length is the value of how big the buffer is going to be, not the actual length to copy
286 *
287 * It is used by RubyString.modify(int) to prevent COW pathological situations
288 * (namely to COW with having <code>length - realSize</code> bytes ahead)
289 */
290 public ByteList dup(int length) {
291 ByteList dup = new ByteList(length);
292
293 dup.append(this.bytes, this.begin, this.realSize);
294 dup.encoding = encoding;
295
296 return dup;
297 }
298
299 /**
300 * Ensure that the bytelist is at least length bytes long. Otherwise grow the backing store
301 * so that it is length bytes long
302 *
303 * @param length to use to make sure ByteList is long enough
304 */
305 public void ensure(int length) {
306 if (length >= bytes.length) {
307 byte[] tmp = new byte[length + (length >>> 1)];
308 System.arraycopy(bytes, begin, tmp, 0, realSize);
309 bytes = tmp;
310 }
311 }
312
313 /**
314 * Make a shared copy of this ByteList. This is used for COW'ing ByteLists, you typically
315 * want a piece of the same backing store to be shared across ByteBuffers, while those
316 * ByteLists will be pointing at different indexes and lengths of the same backing store.
317 *
318 * Note: that this does not update hash or stringValue.
319 *
320 * @param index new begin value for shared ByteBuffer
321 * @param len new length/realSize for chared
322 * @return
323 */
324 public ByteList makeShared(int index, int len) {
325 ByteList shared = new ByteList(bytes, encoding);
326
327 shared.realSize = len;
328 shared.begin = begin + index;
329
330 return shared;
331 }
332
333 /**
334 * Change ByteBuffer to have a new begin that is +index positions past begin with a new length.
335 *
336 * @param index new value to add to begin
337 * @param len the new realSize/length value
338 */
339 public void view(int index, int len) {
340 realSize = len;
341 begin = begin + index;
342 }
343
344 /**
345 * Array copy the byte backing store so that you can guarantee that no other objects are
346 * referencing this objects backing store.
347 */
348 public void unshare() {
349 unshare(realSize);
350 }
351
352 /**
353 * Array copy the byte backing store so that you can guarantee that no other objects are
354 * referencing this objects backing store. This version on unshare allows a length to be
355 * specified which will copy length bytes from the old backing store.
356 *
357 * @param length is the value of how big the buffer is going to be, not the actual length to copy
358 *
359 * It is used by RubyString.modify(int) to prevent COW pathological situations
360 * (namely to COW with having <code>length - realSize</code> bytes ahead)
361 */
362 public void unshare(int length) {
363 byte[] tmp = new byte[length];
364 System.arraycopy(bytes, begin, tmp, 0, Math.min(realSize, length));
365 bytes = tmp;
366 begin = 0;
367 }
368
369 /**
370 * Invalidate the hash and stringValue which may have been cached in this ByteList.
371 */
372 public void invalidate() {
373 hash = 0;
374 stringValue = null;
375 }
376
377 /**
378 * Prepend a byte onto the front of this ByteList.
379 *
380 * @param b is the byte to be prepended
381 */
382 public void prepend(byte b) {
383 grow(1);
384 System.arraycopy(bytes, 0, bytes, 1, realSize);
385 bytes[0] = b;
386 realSize++;
387 }
388
389 /**
390 * Append a single byte to the ByteList
391 *
392 * @param b the byte to be added
393 * @return this instance
394 */
137395 public ByteList append(byte b) {
138396 grow(1);
139397 bytes[realSize++] = b;
140398 return this;
141399 }
142400
401 /**
402 * Append a single int to the ByteList
403 *
404 * @param b the int to be added
405 * @return this instance
406 */
143407 public ByteList append(int b) {
144408 append((byte)b);
145409 return this;
146410 }
147411
412 /**
413 * Append up to length bytes from InputStream to the ByteList. If no bytes are read from the
414 * stream then throw an IOException.
415 *
416 * @param input the stream to read bytes from
417 * @param length how many byte to try and read
418 * @return this instance
419 * @throws IOException when no bytes are read
420 */
148421 public ByteList append(InputStream input, int length) throws IOException {
149422 grow(length);
150423 int read = 0;
162435 return this;
163436 }
164437
438 /**
439 * Append contents of the supplied nio ByteList up to len length onto the end of this
440 * ByteBuffer.
441 *
442 * @param buffer to be appended
443 * @param len is number of bytes you hoping to get from the ByteBuffer
444 */
165445 public void append(ByteBuffer buffer, int len) {
166446 grow(len);
167447 buffer.get(bytes, realSize, len);
168448 realSize += len;
169449 }
170450
171 public void fill(int b, int len) {
172 for ( ; --len >= 0; ) {
173 append(b);
174 }
175 }
176
177 public Object clone() {
178 return dup();
179 }
180
181 public ByteList dup() {
182 ByteList dup = dup(realSize);
183 dup.hash = hash;
184 dup.stringValue = stringValue;
185 return dup;
186 }
187
188 public ByteList shallowDup() {
189 ByteList dup = new ByteList(bytes, false);
190 dup.realSize = realSize;
191 dup.begin = begin;
192 dup.encoding = encoding;
193 dup.hash = hash;
194 dup.stringValue = stringValue;
195 return dup;
196 }
197
198 /**
199 * @param length is the value of how big the buffer is going to be, not the actual length to copy
200 *
201 * It is used by RubyString.modify(int) to prevent COW pathological situations
202 * (namely to COW with having <code>length - realSize</code> bytes ahead)
203 */
204 public ByteList dup(int length) {
205 ByteList dup = new ByteList(false);
206 dup.bytes = new byte[length];
207 // use the smaller of the two sizes for the new real size, to allow truncating
208 int newRealSize = Math.min(length, realSize);
209 System.arraycopy(bytes, begin, dup.bytes, 0, newRealSize);
210 dup.realSize = newRealSize;
211 dup.begin = 0;
212 dup.encoding = encoding;
213 return dup;
214 }
215
216 public void ensure(int length) {
217 if (length >= bytes.length) {
218 byte[]tmp = new byte[length + (length >>> 1)];
219 System.arraycopy(bytes, begin, tmp, 0, realSize);
220 bytes = tmp;
221 }
222 }
223
224 public ByteList makeShared(int index, int len) {
225 ByteList shared = new ByteList(false);
226 shared.bytes = bytes;
227 shared.realSize = len;
228 shared.begin = begin + index;
229 shared.encoding = encoding;
230 return shared;
231 }
232
233 public void view(int index, int len) {
234 realSize = len;
235 begin = begin + index;
236 }
237
238 public void unshare() {
239 unshare(realSize);
240 }
241
242 /**
243 * @param length is the value of how big the buffer is going to be, not the actual length to copy
244 *
245 * It is used by RubyString.modify(int) to prevent COW pathological situations
246 * (namely to COW with having <code>length - realSize</code> bytes ahead)
247 */
248 public void unshare(int length) {
249 byte[] tmp = new byte[length];
250 System.arraycopy(bytes, begin, tmp, 0, Math.min(realSize, length));
251 bytes = tmp;
252 begin = 0;
253 }
254
255 public void invalidate() {
256 hash = 0;
257 stringValue = null;
258 }
259
260 public void prepend(byte b) {
261 grow(1);
262 System.arraycopy(bytes, 0, bytes, 1, realSize);
263 bytes[0] = b;
264 realSize++;
265 }
266
451 /**
452 * Append moreBytes onto the end of the current ByteList.
453 *
454 * @param moreBytes to be added.
455 */
267456 public void append(byte[] moreBytes) {
457 assert moreBytes != null : "moreBytes is null";
458
268459 grow(moreBytes.length);
269460 System.arraycopy(moreBytes, 0, bytes, realSize, moreBytes.length);
270461 realSize += moreBytes.length;
271462 }
272463
464 /**
465 * Append moreBytes onto the end of the current ByteList.
466 *
467 * @param moreBytes to be added.
468 */
273469 public void append(ByteList moreBytes) {
274470 append(moreBytes.bytes, moreBytes.begin, moreBytes.realSize);
275471 }
276472
473 /**
474 * Append moreBytes onto the end of the current ByteList with +index as the new begin for
475 * len bytes from the moreBytes ByteList.
476 *
477 * @param moreBytes to be added.
478 * @param index new index past current begin value
479 * @param len is the number of bytes to append from source ByteList
480 */
277481 public void append(ByteList moreBytes, int index, int len) {
278482 append(moreBytes.bytes, moreBytes.begin + index, len);
279483 }
280484
485 /**
486 * Append moreBytes onto the end of the current ByteList with start as the new begin for
487 * len bytes from the moreBytes byte array.
488 *
489 * @param moreBytes to be added.
490 * @param start is the new begin value
491 * @param len is the number of bytes to append from source byte array
492 */
281493 public void append(byte[] moreBytes, int start, int len) {
494 assert moreBytes != null : "moreBytes is null";
495 assert start >= 0 && (start == 0 || start < moreBytes.length) : "Invalid start";
496 assert len >= 0 && moreBytes.length - start >= len : "Bad length";
497
282498 grow(len);
283499 System.arraycopy(moreBytes, start, bytes, realSize, len);
284500 realSize += len;
285501 }
286502
503 /**
504 * Resize the ByteList's backing store to be length in size. Note that this forces the backing
505 * store to array copy regardless of ByteLists current size or contents. It essentially will
506 * end any COWing.
507 *
508 * @param length the new length for the backing store.
509 */
287510 public void realloc(int length) {
511 assert length >= 0 : "Invalid length";
512 assert length >= realSize : "length is too small";
513
288514 byte tmp[] = new byte[length];
289515 System.arraycopy(bytes, 0, tmp, 0, realSize);
290516 bytes = tmp;
291517 }
292518
519 /**
520 * Return the current length of the ByteList.
521 *
522 * @return the number of bytes in this ByteList.
523 */
293524 public int length() {
294525 return realSize;
295526 }
296527
528 // ENEBO: Wow...what happens if newLength < realSize...nasty shrinkage?
529 /**
530 * grow the bytelist to be newLength in size.
531 *
532 * @param newLength
533 */
534 public void length(int newLength) {
535 // assert newLength >= realSize : "newLength is too small";
536
537 grow(newLength - realSize);
538 realSize = newLength;
539 }
540
541 /**
542 * Number of characters in this ByteList based on its current encoding.
543 *
544 * @return number of characters
545 */
297546 public int lengthEnc() {
298547 return encoding.strLength(bytes, begin, begin + realSize);
299548 }
300549
301 public void length(int newLength) {
302 grow(newLength - realSize);
303 realSize = newLength;
304 }
305
550 /**
551 * Get the byte at index from the ByteList.
552 *
553 * @param index to retreive byte from
554 * @return the byte retreived
555 */
306556 public int get(int index) {
557 assert index >= 0 : "index must be positive";
558
307559 return bytes[begin + index];
308560 }
309561
562 /**
563 * Get the index code point in this ByteList.
564 *
565 * @param index is the element you want
566 * @return the element you requested
567 */
310568 public int getEnc(int index) {
311569 return encoding.strCodeAt(bytes, begin, begin + realSize, index);
312570 }
313571
572 /**
573 * Set the byte at index to be new value.
574 *
575 * @param index to set byte
576 * @param b is the new value.
577 */
314578 public void set(int index, int b) {
579 assert index >= 0 : "index must be positive";
580 assert begin + index < begin + realSize : "index is too large";
581
315582 bytes[begin + index] = (byte)b;
316583 }
317584
585 /**
586 * Replace the byte array backing store with newBytes. This method is only referred to in
587 * deprecated method RubyString.view(CharSequence).
588 *
589 * We deprecated this method because it ignore begin and if we
590 *
591 * @param newBytes
592 */
593 @Deprecated
318594 public void replace(byte[] newBytes) {
319595 assert newBytes != null;
320596 this.bytes = newBytes;
349625 realSize = newSize;
350626 }
351627
628 /**
629 * Note: This is as unsafe as unsafeReplace
630 *
631 * @param beg
632 * @param len
633 * @param nbytes
634 */
352635 public void replace(int beg, int len, ByteList nbytes) {
353636 replace(beg, len, nbytes.bytes, nbytes.begin, nbytes.realSize);
354637 }
355638
639 /**
640 * Note: This is as unsafe as unsafeReplace
641 * @param beg
642 * @param len
643 * @param buf
644 */
356645 public void replace(int beg, int len, byte[] buf) {
357646 replace(beg, len, buf, 0, buf.length);
358647 }
359648
649 /**
650 * Note: This is as unsafe as unsafeReplace
651 * @param beg
652 * @param len
653 * @param nbytes
654 * @param index
655 * @param count
656 */
360657 public void replace(int beg, int len, byte[] nbytes, int index, int count) {
361658 unsafeReplace(beg, len, nbytes, index, count);
362659 }
368665 realSize++;
369666 }
370667
668 /**
669 * Get the index of first occurrence of c in ByteList from the beginning of the ByteList.
670 *
671 * @param c byte to be looking for
672 * @return the index of the byte or -1 if not found
673 */
371674 public int indexOf(int c) {
372675 return indexOf(c, 0);
373676 }
374677
678 /**
679 * Get the index of first occurrence of c in ByteList from the pos offset of the ByteList.
680 *
681 * @param c byte to be looking for
682 * @param pos off set from beginning of ByteList to look for byte
683 * @return the index of the byte or -1 if not found
684 */
375685 public int indexOf(final int c, int pos) {
376686 // not sure if this is checked elsewhere,
377687 // didn't see it in RubyString. RubyString does
386696 return pos < size ? pos - begin : -1;
387697 }
388698
699 /**
700 * Get the index of first occurrence of Bytelist find in this ByteList.
701 *
702 * @param find the ByteList to find
703 * @return the index of the byte or -1 if not found
704 */
389705 public int indexOf(ByteList find) {
390706 return indexOf(find, 0);
391707 }
392708
709 /**
710 * Get the index of first occurrence of Bytelist find in this ByteList starting at index i.
711 *
712 * @param find the ByteList to find
713 * @param i the index to start from
714 * @return the index of the byte or -1 if not found
715 */
393716 public int indexOf(ByteList find, int i) {
394717 return indexOf(bytes, begin, realSize, find.bytes, find.begin, find.realSize, i);
395718 }
396719
720 /**
721 * Get the index of first occurrence of target in source using the offset and count parameters.
722 * fromIndex can be used to start beyond zero on source.
723 *
724 * @return the index of the byte or -1 if not found
725 */
397726 static int indexOf(byte[] source, int sourceOffset, int sourceCount, byte[] target, int targetOffset, int targetCount, int fromIndex) {
398727 if (fromIndex >= sourceCount) return (targetCount == 0 ? sourceCount : -1);
399728 if (fromIndex < 0) fromIndex = 0;
416745 return -1;
417746 }
418747
748 /**
749 * Get the index of last occurrence of c in ByteList from the end of the ByteList.
750 *
751 * @param c byte to be looking for
752 * @return the index of the byte or -1 if not found
753 */
419754 public int lastIndexOf(int c) {
420755 return lastIndexOf(c, realSize - 1);
421756 }
422757
758 /**
759 * Get the index of last occurrence of c in ByteList from the pos offset of the ByteList.
760 *
761 * @param c byte to be looking for
762 * @param pos off set from end of ByteList to look for byte
763 * @return the index of the byte or -1 if not found
764 */
423765 public int lastIndexOf(final int c, int pos) {
424766 // not sure if this is checked elsewhere,
425767 // didn't see it in RubyString. RubyString does
426768 // cast to char, so c will be >= 0.
427 if (c > 255)
428 return -1;
769 if (c > 255) return -1;
770
429771 final byte b = (byte)(c&0xFF);
430772 final int size = begin + realSize;
431773 pos += begin;
439781 return pos - begin;
440782 }
441783
784 /**
785 * Get the index of last occurrence of find in ByteList from the end of the ByteList.
786 *
787 * @param find ByteList to be looking for
788 * @return the index of the byte or -1 if not found
789 */
442790 public int lastIndexOf(ByteList find) {
443791 return lastIndexOf(find, realSize);
444792 }
445793
794 /**
795 * Get the index of last occurrence of find in ByteList from the end of the ByteList.
796 *
797 * @param find ByteList to be looking for
798 * @param pos index from end of list to search from
799 * @return the index of the byte or -1 if not found
800 */
446801 public int lastIndexOf(ByteList find, int pos) {
447802 return lastIndexOf(bytes, begin, realSize, find.bytes, find.begin, find.realSize, pos);
448803 }
449804
805 /**
806 * Get the index of last occurrence of target in source using the offset and count parameters.
807 * fromIndex can be used to start beyond zero on source.
808 *
809 * @return the index of the byte or -1 if not found
810 */
450811 static int lastIndexOf(byte[] source, int sourceOffset, int sourceCount, byte[] target, int targetOffset, int targetCount, int fromIndex) {
451812 int rightIndex = sourceCount - targetCount;
452813 if (fromIndex < 0) return -1;
489850 return true;
490851 }
491852
853 /**
854 * Does this ByteList start with the supplied ByteList?
855 *
856 * @param other is the bytelist to compare with
857 * @return true is this ByteList starts with other
858 */
492859 public boolean startsWith(ByteList other) {
493860 return startsWith(other, 0);
494861 }
495862
863 /**
864 * Does this ByteList end with the supplied ByteList?
865 *
866 * @param other is the bytelist to compare with
867 * @return true is this ByteList starts with other
868 */
496869 public boolean endsWith(ByteList other) {
497870 return startsWith(other, realSize - other.realSize);
498871 }
499872
873 /**
874 * Does this ByteList equal the other ByteList?
875 *
876 * @param other is the bytelist to compare with
877 * @return true is this ByteList is the same
878 */
879 @Override
500880 public boolean equals(Object other) {
501881 if (other instanceof ByteList) return equal((ByteList)other);
502882 return false;
503883 }
504884
885 /**
886 * Does this ByteList equal the other ByteList?
887 *
888 * @param other is the bytelist to compare with
889 * @return true is this ByteList is the same
890 */
505891 public boolean equal(ByteList other) {
506892 if (other == this) return true;
507893 if (hash != 0 && other.hash != 0 && hash != other.hash) return false;
526912 return false;
527913 }
528914
529 // an alternative to the new version of equals, should
530 // detect inequality faster (in many cases), but is slow
531 // in the case of equal values (all bytes visited), due to
532 // using n+=2, n-=2 vs. ++n, --n while iterating over the array.
915 /**
916 * an alternative to the new version of equals, should
917 * detect inequality faster (in many cases), but is slow
918 * in the case of equal values (all bytes visited), due to
919 * using n+=2, n-=2 vs. ++n, --n while iterating over the array.
920 */
533921 public boolean sample_equals(Object other) {
534922 if (other == this) return true;
535923 if (other instanceof ByteList) {
560948 return cmp((ByteList)other);
561949 }
562950
951 /**
952 * This comparison matches MRI comparison of Strings (rb_str_cmp).
953 */
563954 public int cmp(final ByteList other) {
564955 if (other == this) return 0;
565956 final int size = realSize;
578969 return size == other.realSize ? 0 : size == len ? -1 : 1;
579970 }
580971
972 /**
973 * Do a case insensitive comparison with other ByteList with return types similiar to compareTo.
974 *
975 * @param other the ByteList to compare
976 * @return -1, 0, or 1
977 */
581978 public int caseInsensitiveCmp(final ByteList other) {
582979 if (other == this) return 0;
583980
6091006 return bytes;
6101007 }
6111008
1009 /**
1010 * Get a copy of the bytes referenced by this ByteList. It will make an optimal copy and not
1011 * carry along unused bytes from COW sharing.
1012 *
1013 * @return a copy of the bytes.
1014 */
6121015 public byte[] bytes() {
6131016 byte[] newBytes = new byte[realSize];
6141017 System.arraycopy(bytes, begin, newBytes, 0, realSize);
6151018 return newBytes;
6161019 }
6171020
1021 /**
1022 * First index of the backing array that contains data for the ByteList. Note that we have
1023 * copy-on-write (COW) semantics which means sharing the same backing store will yield different
1024 * begin and size values while using the same byte[].
1025 *
1026 * @return the index
1027 */
6181028 public int begin() {
6191029 return begin;
6201030 }
6211031
1032 /**
1033 * Grow the ByteList by increaseRequested bytes. A value <0 will be a no-op.
1034 *
1035 * @param increaseRequested number of bytes to grow
1036 */
6221037 private void grow(int increaseRequested) {
6231038 if (increaseRequested < 0) return;
6241039
6301045 }
6311046 }
6321047
1048 /**
1049 * @see Object#hashCode()
1050 */
1051 @Override
6331052 public int hashCode() {
6341053 if (hash != 0) return hash;
6351054
6491068 *
6501069 * @return an ISO-8859-1 representation of the byte list
6511070 */
1071 @Override
6521072 public String toString() {
6531073 if (stringValue == null) {
6541074 stringValue = decode(bytes, begin, realSize, "ISO-8859-1");
6561076 return stringValue;
6571077 }
6581078
1079 /**
1080 * Create a bytelist with ISO_8859_1 encoding from the provided CharSequence.
1081 *
1082 * @param s the source for new ByteList
1083 * @return the new ByteList
1084 */
6591085 public static ByteList create(CharSequence s) {
6601086 return new ByteList(plain(s),false);
6611087 }
6621088
1089 /**
1090 * Create a byte[] from a CharSequence assuming a raw/ISO-8859-1 encoding
1091 *
1092 * @param s the CharSequence to convert
1093 * @return a byte[]
1094 */
6631095 public static byte[] plain(CharSequence s) {
664 if (s instanceof String) {
665 return encode(s, "ISO-8859-1");
666 }
1096 if (s instanceof String) return encode(s, "ISO-8859-1");
1097
1098 // Not a String...get it the slow way
6671099 byte[] bytes = new byte[s.length()];
6681100 for (int i = 0; i < bytes.length; i++) {
6691101 bytes[i] = (byte) s.charAt(i);
6711103 return bytes;
6721104 }
6731105
1106 /**
1107 * Create a byte[] from a char[] assuming a raw/ISO-8859-1 encoding
1108 *
1109 * @param s the CharSequence to convert
1110 * @return a byte[]
1111 */
6741112 public static byte[] plain(char[] s) {
6751113 byte[] bytes = new byte[s.length];
6761114 for (int i = 0; i < s.length; i++) {
6791117 return bytes;
6801118 }
6811119
1120 /**
1121 * Create a char[] from a byte[] assuming a raw/ISO-8859-1 encoding
1122 *
1123 * @param b the source byte[]
1124 * @param start index to start converting to char's
1125 * @param length how many bytes to convert to char's
1126 * @return a byte[]
1127 */
6821128 public static char[] plain(byte[] b, int start, int length) {
1129 assert b != null : "byte array cannot be null";
1130 assert start >= 0 && start + length <= b.length : "Invalid start or start+length too long";
1131
6831132 char[] chars = new char[length];
6841133 for (int i = 0; i < length; i++) {
6851134 chars[i] = (char) (b[start + i] & 0xFF);
6871136 return chars;
6881137 }
6891138
1139 /**
1140 * Create a char[] from a byte[] assuming a raw/ISO-8859-1 encoding
1141 *
1142 * @param b the source byte[]
1143 * @return a byte[]
1144 */
6901145 public static char[] plain(byte[] b) {
1146 assert b != null : "byte array cannot be null";
1147
6911148 char[] chars = new char[b.length];
6921149 for (int i = 0; i < b.length; i++) {
6931150 chars[i] = (char) (b[i] & 0xFF);
7001157 private static final ConcurrentMap<String,Charset> charsetsByAlias =
7011158 new ConcurrentHashMap<String,Charset>();
7021159
1160 /**
1161 * Decode byte data into a String with the supplied charsetName.
1162 *
1163 * @param data to be decoded
1164 * @param offset where to start decoding from in data
1165 * @param length how many bytes to decode from data
1166 * @param charsetName used to make the resulting String
1167 * @return the new String
1168 */
7031169 public static String decode(byte[] data, int offset, int length, String charsetName) {
704 Charset cs = lookup(charsetName);
705 return cs.decode(ByteBuffer.wrap(data, offset, length)).toString();
706 }
707
1170 return lookup(charsetName).decode(ByteBuffer.wrap(data, offset, length)).toString();
1171 }
1172
1173 /**
1174 * Decode byte data into a String with the supplied charsetName.
1175 *
1176 * @param data to be decoded
1177 * @param charsetName used to make the resulting String
1178 * @return the new String
1179 */
7081180 public static String decode(byte[] data, String charsetName) {
709 Charset cs = lookup(charsetName);
710 return cs.decode(ByteBuffer.wrap(data)).toString();
711 }
712
1181 return lookup(charsetName).decode(ByteBuffer.wrap(data)).toString();
1182 }
1183
1184 /**
1185 * Encode CharSequence into a set of bytes based on the charsetName.
1186 *
1187 * @param data to be encoded
1188 * @param charsetName used to extract the resulting bytes
1189 * @return the new byte[]
1190 */
7131191 public static byte[] encode(CharSequence data, String charsetName) {
714 Charset cs = lookup(charsetName);
715 return cs.encode(CharBuffer.wrap(data)).array();
1192 return lookup(charsetName).encode(CharBuffer.wrap(data)).array();
7161193 }
7171194
7181195 private static Charset lookup(String alias) {
7241201 return cs;
7251202 }
7261203
1204 /**
1205 * Pretend byte array is raw and each byte is also the character value
1206 *
1207 * @param ix is the index you want
1208 * @return
1209 */
7271210 public char charAt(int ix) {
7281211 return (char)(this.bytes[begin + ix] & 0xFF);
7291212 }
7301213
1214 /**
1215 * Create subSequence of this array between start and end offsets
1216 *
1217 * @param start index for beginning of subsequence
1218 * @param end index for end of subsequence
1219 * @return a new ByteList/CharSequence
1220 */
7311221 public CharSequence subSequence(int start, int end) {
7321222 return new ByteList(this, start, end - start);
7331223 }
7341224
1225 /**
1226 * Are these two byte arrays similiar (semantics similiar too compareTo). This is slightly
1227 * special in that it will only compare the same number of bytes based on the lesser of the two
1228 * lengths.
1229 *
1230 * @return -1, 0, 1
1231 */
7351232 public static int memcmp(final byte[] first, final int firstStart, final int firstLen, final byte[] second, final int secondStart, final int secondLen) {
7361233 if (first == second) return 0;
7371234 final int len = Math.min(firstLen,secondLen);
7441241
7451242 }
7461243
1244 /**
1245 * Are these two byte arrays similiar (semantics similiar too compareTo).
1246 *
1247 * @return -1, 0, 1
1248 */
7471249 public static int memcmp(final byte[] first, final int firstStart, final byte[] second, final int secondStart, final int len) {
7481250 if (first == second) return 0;
7491251 int offset = -1;