001package org.unix4j.line; 002 003 004/** 005 * A {@link Line} implementation based on a single {@link CharSequence} such as 006 * a {@link StringBuilder} or {@link String}. The sequence starts with the 007 * {@link #getContent() content} string and ends with the 008 * {@link #getLineEnding() line ending}. 009 * <p> 010 * As opposed to this implementation, the {@link SimpleLine} consists of two 011 * separate character sequences for content and line ending. 012 */ 013public class SingleCharSequenceLine implements Line { 014 015 private final CharSequence charSequence; 016 private final int offset; 017 private final int contentLength; 018 private final int lineEndingLength; 019 private String content = null; 020 021 /** 022 * Constructor with character sequence with the data and the 023 * {@code lineEndingLength} indicating whether there is one or two 024 * characters for the line ending. The character sequence is read from the 025 * first character with offset zero. 026 * 027 * @param charSequence 028 * the character sequence containing the data 029 * @param lineEndingLength 030 * the number of characters making up the line ending; must be 031 * one or two 032 * @throws IllegalArgumentException 033 * if {@code lineEndingLength} is negative or larger than two 034 */ 035 public SingleCharSequenceLine(CharSequence charSequence, int lineEndingLength) { 036 this(charSequence, 0, charSequence.length() - lineEndingLength, lineEndingLength); 037 } 038 039 /** 040 * Constructor with character sequence with the data and {@code offset} 041 * pointing to the first content character of the line. The 042 * {@code contentLength} and {@code lineEndingLength} parameters define the 043 * respective parts in {@code buffer}. 044 * 045 * @param charSequence 046 * the character sequence containing the data 047 * @param offset 048 * the offset containing the first character of line 049 * @param contentLength 050 * the number of characters making up the content of the line 051 * without line ending; must be non-negative 052 * @param lineEndingLength 053 * the number of characters making up the line ending; must be 054 * zero, one or two (zero only for the last line) 055 * @throws IllegalArgumentException 056 * if {@code offset} or {@code contentLength} are negative or 057 * {@code lineEndingLength} is negative or larger than two 058 * @throws IndexOutOfBoundsException 059 * if the buffer length is smaller than 060 * {@code offset+contentLength+lineEndingLength} 061 */ 062 public SingleCharSequenceLine(CharSequence charSequence, int offset, int contentLength, int lineEndingLength) { 063 if (offset < 0) { 064 throw new IllegalArgumentException("offset must be non-negative, but was found to be " + offset); 065 } 066 if (contentLength < 0) { 067 throw new IllegalArgumentException("contentLength must be non-negative, but was found to be " + contentLength); 068 } 069 if (lineEndingLength < 0 || lineEndingLength > 2) { 070 throw new IllegalArgumentException("lineEndingLength must between zero and two, but was found to be " + lineEndingLength); 071 } 072 if (offset + contentLength + lineEndingLength > charSequence.length()) { 073 throw new IndexOutOfBoundsException("line end is after charSequence end: " + (offset + contentLength + lineEndingLength) + " > " + charSequence.length()); 074 } 075 this.charSequence = charSequence; 076 this.offset = offset; 077 this.contentLength = contentLength; 078 this.lineEndingLength = lineEndingLength; 079 } 080 081 @Override 082 public int length() { 083 return contentLength + lineEndingLength; 084 } 085 086 @Override 087 public char charAt(int index) { 088 return charSequence.charAt(offset + index); 089 } 090 091 @Override 092 public CharSequence subSequence(int start, int end) { 093 return charSequence.subSequence(offset + start, offset + end); 094 } 095 096 @Override 097 public String getContent() { 098 if (content == null) { 099 content = charSequence.subSequence(offset, offset + contentLength).toString(); 100 } 101 return content; 102 } 103 104 @Override 105 public int getContentLength() { 106 return contentLength; 107 } 108 109 @Override 110 public String getLineEnding() { 111 return charSequence.subSequence(offset + contentLength, offset + contentLength + lineEndingLength).toString(); 112 } 113 114 @Override 115 public int getLineEndingLength() { 116 return lineEndingLength; 117 } 118 119 @Override 120 public String toString() { 121 return charSequence.subSequence(offset, offset + contentLength + lineEndingLength).toString(); 122 } 123 124 @Override 125 public int hashCode() { 126 return toString().hashCode(); 127 } 128 129 @Override 130 public boolean equals(Object obj) { 131 if (obj == this) 132 return true; 133 if (obj instanceof Line) { 134 return toString().equals(obj.toString()); 135 } 136 return false; 137 } 138 139}