Bladeren bron

#37 javadoc: text

Ranides Atterwim 4 jaren geleden
bovenliggende
commit
4525c6bf8c

+ 425 - 44
assira.core/src/main/java/net/ranides/assira/text/StrBuffer.java

@@ -19,6 +19,23 @@ import net.ranides.assira.collection.arrays.NativeArrayUtils;
 import net.ranides.assira.math.MathUtils;
 
 /**
+ * This class is alternative to java StringBuilder:
+ *  - it offers a bit more methods for appending
+ *  - it supports "printf" append
+ *  - it supports appending list of items (using some join separator)
+ *  - it can be converted to Reader/Writer views
+ *
+ *  MOST IMPORTANT DIFFERENCE:
+ *  It has constant capacity and internal buffer can't be reallocated.
+ *  You must reserve enough space in advance, at creation time.
+ *
+ *  Other StrBuilder differences:
+ *   - It does not support nested options
+ *   - It does not support appending null values
+ *   - It does not check bounds
+ *
+ *  Because of that is could be faster than {@link StrBuilder} or StringBuilder,
+ *  but at the cost of flexibility and ease of use.
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
@@ -38,23 +55,56 @@ public class StrBuffer implements Appendable, CharSequence, Serializable {
 
     private final BuilderState options = new BuilderState();
 
+    /**
+     * Creates new StrBuffer with defined capacity.
+     * Please remember, that you can't reallocate created buffer later, so choose this value carefully.
+     *
+     * @param capacity capacity
+     */
     public StrBuffer(int capacity) {
         this.buffer = new char[capacity];
     }
 
+    /**
+     * Returns buffer options.
+     * Buffer uses those options all the time and "open"/"close" methods does not stack state.
+     *
+     * @return StrBuilderOptions
+     */
     public StrBuilderOptions options() {
         return options;
     }
-    
+
+    /**
+     * Returns current size of buffer
+     *
+     * @return int
+     */
     @Override
     public int length() {
         return size;
     }
-    
+
+    /**
+     * Returns maximal size of buffer
+     *
+     * @return int
+     */
     public int capacity() {
         return buffer.length;
     }
-    
+
+    /**
+     * Changes size of content stored the buffer.
+     * If content is longer than "length", some data will be discarded.
+     * If content is shorter than "length", it will append "c" characters.
+     *
+     * Please note, that "length" can't be greater than "capacity".
+     *
+     * @param length length
+     * @param c c
+     * @return this
+     */
     public StrBuffer resize(int length, char c) {
         if (length < 0) {
             throw new IllegalArgumentException("negative size: " + length);
@@ -69,99 +119,251 @@ public class StrBuffer implements Appendable, CharSequence, Serializable {
         size = length;
         return this;
     }
-    
+
+    /**
+     * Clears data appended into this buffer
+     *
+     * @return this
+     */
     public StrBuffer clear() {
         size = 0;
         return this;
     }
-    
+
+    /**
+     * Returns the char value at the specified index.
+     *
+     * Please note that it does not care about current size of the buffer.
+     * If you read characters exceeding "size" some garbage will be returned.
+     *
+     * @param index index
+     * @return char
+     */
     @Override
     public char charAt(int index) {
         return buffer[index];
     }
-    
+
+    /**
+     * Changes character inside buffer at specified position.
+     *
+     * It does not care about current size of the buffer.
+     * You can change characters exceeding "size", altough it is pretty useless operation.
+     *
+     * @param index index
+     * @param value value
+     * @return this
+     */
     public StrBuffer setCharAt(int index, char value) {
         buffer[index] = value;
         return this;
     }
 
+    /**
+     * Returns subsequence which is view of this buffer.
+     * Every change inside buffer will be visible in returned CharSequence
+     *
+     * It does not care about current size of the buffer.
+     * If you specify out of bounds indexes, some returned characters will be garbage.
+     *
+     * @param begin begin
+     * @param end end
+     * @return CharSequence
+     */
     @Override
     public CharSequence subSequence(int begin, int end) {
         return StringUtils.wrap(buffer, begin, end);
     }
-    
+
+    /**
+     * Returns new array with current data copied into it
+     *
+     * @return copy
+     */
     public char[] getChars() {
         return getChars(0, size);
     }
-    
+
+    /**
+     * Returns new array with fragment of current data copied into it
+     *
+     * It does not care about current size of the buffer.
+     * If you specify out of bounds indexes, some returned characters will be garbage.
+     *
+     * @param begin begin
+     * @param end end
+     * @return copy
+     */
     public char[] getChars(int begin, int end) {
         if (end == begin) {
             return StrBuffer.EMPTY;
         }
         return ArrayUtils.slice(buffer, begin, end);
     }
-    
+
+    /**
+     * Copies current data into provided array.
+     *
+     * @param target target
+     * @return target
+     */
     public char[] getChars(char[] target) {
         return getChars(0, size, target, 0);
     }
-    
+
+    /**
+     * Copies fragment of current data into provided array
+     * Copy operation will start writing to array from "offset"
+     *
+     * @param begin begin
+     * @param end end
+     * @param target target
+     * @param offset offset
+     * @return target
+     */
     public char[] getChars(int begin, int end, char[] target, int offset) {
         System.arraycopy(buffer, begin, target, offset, end - begin);
         return target;
     }
-    
-    public String getRightFragment(int length) {
-        int n = MathUtils.clip(length, 0, size);
-        return new String(buffer, size - n, n);
-    }
 
-    public String getLeftFragment(int length) {
+    /**
+     * Returns string with "length" leading characters.
+     *
+     * @param length length
+     * @return String
+     */
+    public String getHeadFragment(int length) {
         return new String(buffer, 0, MathUtils.clip(length, 0, size));
     }
 
+    /**
+     * Returns string with "length" trailing characters.
+     *
+     * @param length length
+     * @return String
+     */
+    public String getTailFragment(int length) {
+        int n = MathUtils.clip(length, 0, size);
+        return new String(buffer, size - n, n);
+    }
+
+    /**
+     * Reverses characters inside buffer.
+     *
+     * @return this
+     */
     public StrBuffer reverse() {
         NativeArrayUtils.reverse(NativeArray.wrap(buffer), size);
         return this;
     }
-    
+
+    /**
+     * Starts new block in list mode.
+     * Nested blocks are not supported, so if there was opened block, it will be discarded.
+     *
+     * Appends to the buffer "options.open" string
+     *
+     * @return this
+     */
     public StrBuffer open() {
         return StrBuffer.this.append(options.reset().open());
     }
 
+    /**
+     * Starts new block in list mode.
+     * Nested blocks are not supported, so if there was opened block, it will be discarded.
+     *
+     * Appends to the buffer "open" string
+     *
+     * @param open open
+     * @return this
+     */
     public StrBuffer open(String open) {
         options.open(open);
         return open();
     }
 
+    /**
+     * Starts new block in list mode.
+     * Nested blocks are not supported, so if there was opened block, it will be discarded.
+     *
+     * Appends to the buffer "open" string
+     * Closing block will append "close" string
+     *
+     * @param open open
+     * @param close close
+     * @return this
+     */
     public StrBuffer open(String open, String close) {
         options.open(open).close(close);
         return open();
     }
 
+    /**
+     * Starts new block in list mode.
+     * Nested blocks are not supported, so if there was opened block, it will be discarded.
+     *
+     * Appends to the buffer "open" string
+     * Closing block will append "close" string
+     * Inserted items will be separated by "separator"
+     *
+     * @param open open
+     * @param close close
+     * @param separator separator
+     * @return this
+     */
     public StrBuffer open(String open, String close, String separator) {
         options.open(open).close(close).separator(separator);
         return open();
     }
-    
+
+    /**
+     * Closes current block.
+     * Strictly speaking: it does not care if any block was opened before.
+     *
+     * Appends to the buffer "close" string
+     *
+     * @return this
+     */
     public StrBuffer close() {
         return StrBuffer.this.append(options.close());
     }
 
+    /**
+     * If you want to insert some values into block, separated by "separator", you can use this method.
+     * It should be called BEFORE each appended item.
+     *
+     * Appends to the buffer "separator" string if it is not first call inside current block.
+     *
+     * @return this
+     */
     public StrBuffer item() {
         if(0 != options.counter++) {
             StrBuffer.this.append(options.separator());
         }
         return this;
     }
-    
+
+    /**
+     * Appends new line separator as configured in options.
+     *
+     * @return this
+     */
     public StrBuffer endl() {
         return StrBuffer.this.append(options.endl());
     }
-    
+
+    /**
+     * Appends blank value.
+     *
+     * Please note that StrBuffer does not support blank values: it does nothing.
+     *
+     * @return this
+     */
     public StrBuffer append() {
         return this;
     }
-    
+
     @Override
     public StrBuffer append(CharSequence value) {
         return append(value, 0, value.length());
@@ -174,44 +376,100 @@ public class StrBuffer implements Appendable, CharSequence, Serializable {
         }
         return this;
     }
-    
+
+    /**
+     * Appends string into buffer
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(String value) {
         return append(value, 0, value.length());
     }
-    
+
+    /**
+     * Appends fragment of string into buffer
+     *
+     * @param value value
+     * @param begin begin
+     * @param end end
+     * @return this
+     */
     public StrBuffer append(String value, int begin, int end) {
         int n = end - begin;
         value.getChars(begin, end, buffer, size);
         size += n;
         return this;
     }
-    
+
+    /**
+     * Appends StringBuffer into buffer
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(StringBuffer value) {
         return append(value, 0, value.length());
     }
-    
+
+    /**
+     * Appends fragment of StringBuffer into buffer
+     *
+     * @param value value
+     * @param begin begin
+     * @param end end
+     * @return this
+     */
     public StrBuffer append(StringBuffer value, int begin, int end) {
         int n = end - begin;
         value.getChars(begin, end, buffer, size);
         size += n;
         return this;
     }
-    
+
+    /**
+     * Appends StringBuilder into buffer
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(StringBuilder value) {
         return append(value, 0, value.length());
     }
-    
+
+    /**
+     * Appends fragment of StringBuilder into buffer
+     *
+     * @param value value
+     * @param begin begin
+     * @param end end
+     * @return this
+     */
     public StrBuffer append(StringBuilder value, int begin, int end) {
         int n = end - begin;
         value.getChars(begin, end, buffer, size);
         size += n;
         return this;
     }
-    
+
+    /**
+     * Appends chars into buffer
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(char[] value) {
         return append(value, 0, value.length);
     }
-    
+
+    /**
+     * Appends fragment of chars into buffer
+     *
+     * @param value value
+     * @param begin begin
+     * @param end end
+     * @return this
+     */
     public StrBuffer append(char[] value, int begin, int end) {
         int n = end - begin;
         System.arraycopy(value, begin, buffer, size, n);
@@ -224,43 +482,117 @@ public class StrBuffer implements Appendable, CharSequence, Serializable {
         buffer[size++] = c;
         return this;
     }
-    
+
+    /**
+     * Appends value into buffer.
+     * Converts object using "toString" method.
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(Object value) {
         return append(value.toString());        
     }
-    
+
+    /**
+     * Appends value into buffer.
+     * Converts boolean to "true" or "false" string
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(boolean value) {
         return append(value ? "true" : "false");
     }
-    
+
+    /**
+     * Appends value into buffer.
+     * Converts value using "String.valueOf"
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(int value) {
         return append(String.valueOf(value));
     }
-    
+
+    /**
+     * Appends value into buffer.
+     * Converts value using "String.valueOf"
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(long value) {
         return append(String.valueOf(value));
     }
 
+    /**
+     * Appends value into buffer.
+     * Converts value using "String.valueOf"
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(float value) {
         return append(String.valueOf(value));
     }
 
+    /**
+     * Appends value into buffer.
+     * Converts value using "String.valueOf"
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuffer append(double value) {
         return append(String.valueOf(value));
     }
-    
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "String.valueOf"
+     *
+     * @param values values
+     * @return this
+     */
     public StrBuffer append(Iterable<?> values) {
         return append(values.iterator(), Object::toString);
     }
-    
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "function"
+     *
+     * @param values values
+     * @param function function
+     * @param <T> T
+     * @return this
+     */
     public <T> StrBuffer append(Iterable<? extends T> values, Function<? super T,String> function) {
         return append(values.iterator(), function);
     }
-    
-    public <T> StrBuffer append(Iterator<? extends T> values) {
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "String.valueOf"
+     *
+     * @param values values
+     * @return this
+     */
+    public StrBuffer append(Iterator<?> values) {
         return append(values, Object::toString);
     }
-    
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "function"
+     *
+     * @param values values
+     * @param function function
+     * @param <T> T
+     * @return this
+     */
     public <T> StrBuffer append(Iterator<? extends T> values, Function<? super T,String> function) {
         if ( !values.hasNext() ) {
             return this;
@@ -275,11 +607,28 @@ public class StrBuffer implements Appendable, CharSequence, Serializable {
             append(separator);
         }
     }
-    
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "String.valueOf"
+     *
+     * @param values values
+     * @param <T> T
+     * @return this
+     */
     public <T> StrBuffer append(T[] values) {
         return append(values, Object::toString);
     }
-    
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "function"
+     *
+     * @param values values
+     * @param function function
+     * @param <T> T
+     * @return this
+     */
     public <T> StrBuffer append(T[] values, Function<? super T,String> function) {
         if ( 0==values.length ) {
             return this;
@@ -291,12 +640,26 @@ public class StrBuffer implements Appendable, CharSequence, Serializable {
         }
         return this;
     }
-    
-    public <T> StrBuffer append(NativeArray values) {
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "String.valueOf"
+     *
+     * @param values values
+     * @return this
+     */
+    public StrBuffer append(NativeArray values) {
         return append(values.size(), i -> String.valueOf(values.get(i)));
     }
-    
-    public <T> StrBuffer append(int size, IntFunction<String> function) {
+
+    /**
+     * Appends "size" values generated by "function", separating them using "options.separator".
+     *
+     * @param size size
+     * @param function function
+     * @return this
+     */
+    public StrBuffer append(int size, IntFunction<String> function) {
         if ( 0==size ) {
             return this;
         }
@@ -357,14 +720,32 @@ public class StrBuffer implements Appendable, CharSequence, Serializable {
         return new String(buffer, 0, size);
     }
 
+    /**
+     * Creates new StringBuilder with buffer content.
+     * StringBuilder capacity is exactly current size.
+     *
+     * @return StringBuilder
+     */
     public StringBuilder toBuilder() {
         return new StringBuilder(size).append(buffer, 0, size);
     }
 
+    /**
+     * Returns new instance of Writer view.
+     * Writer can be used to change buffer and vice versa.
+     *
+     * @return Writer
+     */
     public Writer asWriter() {
         return new SWriter();
     }
 
+    /**
+     * Returns new instance of Reader view.
+     * Changes inside buffer will be visible in Reader.
+     *
+     * @return Reader
+     */
     public Reader asReader() {
         return new SReader();
     }

+ 471 - 51
assira.core/src/main/java/net/ranides/assira/text/StrBuilder.java

@@ -24,6 +24,14 @@ import net.ranides.assira.generic.ValueUtils;
 import net.ranides.assira.math.MathUtils;
 
 /**
+ * This class is alternative to java StringBuilder:
+ *  - it offers a bit more methods for appending
+ *  - it supports "printf" append
+ *  - it supports appending list of items (using some join separator)
+ *  - it can be converted to Reader/Writer views
+ *
+ *  Configuration options (for example list separators) could be configured independently in every opened scope
+ *
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
@@ -35,7 +43,7 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
     
     private static final long serialVersionUID = 1L;
     
-    private static final StrBuilderOptions OPTIONS = new StrBuilderOptions();
+    private static final StrBuilderOptions OPTIONS = new StrBuilderOptions() { };
     
     protected static final char[] EMPTY = new char[0];
     
@@ -48,29 +56,68 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
     private final Supplier<Formatter> formatter = LazyReference.unique(() -> new Formatter(this));
 
     final Deque<BuilderState> options = new ArrayDeque<>();
-    
+
+    /**
+     * Creates new builder with default capacity
+     */
     public StrBuilder() {
         this(CAPACITY);
     }
 
+    /**
+     * Creates new builder with specified capacity
+     *
+     * @param capacity capacity
+     */
     public StrBuilder(int capacity) {
         buffer = new char[capacity];
         options.push(new BuilderState(OPTIONS));
     }
-    
+
+    /**
+     * Returns options for current block.
+     *
+     * StrBuilder supports nested blocks marked by "open" and "close" methods.
+     * Nested blocks inherit options from parent block, but can be modified without affecting other blocks.
+     *
+     * For example, you can open block, override separator, append some items and forget after close.
+     * Your change won't brake later usages of separator in former blocks.
+     *
+     * @return options
+     */
     public StrBuilderOptions options() {
         return options.peek();
     }
-    
+
+    /**
+     * Returns current size of buffer
+     *
+     * @return int
+     */
     @Override
     public int length() {
         return size;
     }
 
+    /**
+     * Returns current size of internal buffer.
+     * Capacity is automatically increased on demand.
+     *
+     * @return int
+     */
     public int capacity() {
         return buffer.length;
     }
-    
+
+    /**
+     * Changes size of content stored the buffer.
+     * If content is longer than "length", some data will be discarded.
+     * If content is shorter than "length", it will append "c" characters.
+     *
+     * @param length length
+     * @param c c
+     * @return this
+     */
     public StrBuilder resize(int length, char c) {
         if (length < 0) {
             throw new IllegalArgumentException("negative size: " + length);
@@ -83,22 +130,47 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         return this;
     }
 
+    /**
+     * Allocates space for internal buffer.
+     * If buffer is larger than specified "capacity", it does nothing.
+     *
+     * @param capacity capacity
+     * @return this
+     */
     public StrBuilder reserve(int capacity) {
         buffer = ArrayAllocator.grow(buffer, capacity, size);
         return this;
     }
 
+    /**
+     * Reallocates internal buffer to current "size"
+     *
+     * @return this
+     */
     public StrBuilder trim() {
         return trim(size);
     }
-    
+
+    /**
+     * Reallocates internal buffer to specified size "n".
+     *
+     * Please note that it preserves current content, so trimmed buffer can be larger than "n"
+     *
+     * @param n n
+     * @return this
+     */
     public StrBuilder trim(int n) {
         if (buffer.length > n && buffer.length!=Math.max(n,size)) {
             buffer = ArrayAllocator.trim(buffer, Math.max(n,size));
         }
         return this;
     }
-    
+
+    /**
+     * Clears data appended into this buffer
+     *
+     * @return this
+     */
     public StrBuilder clear() {
         size = 0;
         BuilderState state = options.peek().copy();
@@ -112,23 +184,50 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         StringUtils.checkIndex(size, index);
         return buffer[index];
     }
-    
+
+    /**
+     * Changes character inside buffer at specified position.
+     *
+     * @param index index
+     * @param value value
+     * @return this
+     */
     public StrBuilder setCharAt(int index, char value) {
         StringUtils.checkIndex(size, index);
         buffer[index] = value;
         return this;
     }
 
+    /**
+     * Returns subsequence which is view of this buffer.
+     * Every change inside buffer will be visible in returned CharSequence
+     *
+     * @param begin begin
+     * @param end end
+     * @return CharSequence
+     */
     @Override
     public CharSequence subSequence(int begin, int end) {
         NativeArrayAllocator.ensureFromTo(size, begin, end);
         return StringUtils.wrap(buffer, begin, end);
     }
-        
+
+    /**
+     * Returns new array with current data copied into it
+     *
+     * @return copy
+     */
     public char[] getChars() {
         return getChars(0, size);
     }
-    
+
+    /**
+     * Returns new array with fragment of current data copied into it
+     *
+     * @param begin begin
+     * @param end end
+     * @return copy
+     */
     public char[] getChars(int begin, int end) {
         StringUtils.checkRange(size, begin, end);
         if (end == begin) {
@@ -136,58 +235,148 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         }
         return ArrayUtils.slice(buffer, begin, end);
     }
-    
+
+    /**
+     * Copies current data into provided array.
+     *
+     * @param target target
+     * @return target
+     */
     public char[] getChars(char[] target) {
         return getChars(0, size, target, 0);
     }
-    
+
+    /**
+     * Copies fragment of current data into provided array
+     * Copy operation will start writing to array from "offset"
+     *
+     * @param begin begin
+     * @param end end
+     * @param target target
+     * @param offset offset
+     * @return target
+     */
     public char[] getChars(int begin, int end, char[] target, int offset) {
         StringUtils.checkRange(size, begin, end);
         System.arraycopy(buffer, begin, target, offset, end - begin);
         return target;
     }
-    
-    public String getRightFragment(int length) {
+
+    /**
+     * Returns string with "length" leading characters.
+     *
+     * @param length length
+     * @return String
+     */
+    public String getHeadFragment(int length) {
+        return new String(buffer, 0, MathUtils.clip(length, 0, size));
+    }
+
+    /**
+     * Returns string with "length" trailing characters.
+     *
+     * @param length length
+     * @return String
+     */
+    public String getTailFragment(int length) {
         int n = MathUtils.clip(length, 0, size);
         return new String(buffer, size - n, n);
     }
-    
-    public String getLeftFragment(int length) {
-        return new String(buffer, 0, MathUtils.clip(length, 0, size));
-    }
-    
+
+    /**
+     * Reverses characters inside buffer.
+     *
+     * @return this
+     */
     public StrBuilder reverse() {
         NativeArrayUtils.reverse(NativeArray.wrap(buffer), size);
         return this;
     }
-    
+
+    /**
+     * Starts new block in list mode.
+     * Current opened block is stacked and will be restored on close.
+     *
+     * Appends to the buffer "options.open" string
+     *
+     * @return this
+     */
     public StrBuilder open() {
         options.push(options.peek().derive());
         return append(options.peek().open());
     }
-    
+
+    /**
+     * Starts new block in list mode.
+     * Current opened block is stacked and will be restored on close.
+     *
+     * Appends to the buffer "open" string
+     *
+     * @param open open
+     * @return this
+     */
     public StrBuilder open(String open) {
         options.push(options.peek().derive().open(open));
         return append(open);
     }
-    
+
+    /**
+     * Starts new block in list mode.
+     * Current opened block is stacked and will be restored on close.
+     *
+     * Appends to the buffer "open" string
+     * Closing block will append "close" string
+     *
+     * @param open open
+     * @param close close
+     * @return this
+     */
     public StrBuilder open(String open, String close) {
         options.push(options.peek().derive().open(open).close(close));
         return append(open);
     }
-    
+
+    /**
+     * Starts new block in list mode.
+     * Current opened block is stacked and will be restored on close.
+     *
+     * Appends to the buffer "open" string
+     * Closing block will append "close" string
+     * Inserted items will be separated by "separator"
+     *
+     * @param open open
+     * @param close close
+     * @param separator separator
+     * @return this
+     */
     public StrBuilder open(String open, String close, String separator) {
         options.push(options.peek().derive().open(open).close(close).separator(separator));
         return append(open);
     }
-    
+
+    /**
+     * Closes current block.
+     * Restores state of previously opened block, if any.
+     *
+     * Appends to the buffer "close" string
+     *
+     * @return this
+     */
     public StrBuilder close() {
         if(options.size() <= 1) {
             throw new IllegalStateException("There is not block to close.");
         }
         return append(options.pop().close());
     }
-    
+
+    /**
+     * If you want to insert some values into block, separated by "separator", you can use this method.
+     * It should be called BEFORE each appended item.
+     *
+     * Appends to the buffer "separator" string if it is not first call inside current block.
+     *
+     * @return this
+     */
     public StrBuilder item() {
         BuilderState state = options.peek();
         if(0 != state.counter++) {
@@ -195,11 +384,21 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         }
         return this;
     }
-    
+
+    /**
+     * Appends new line separator as configured in options for current block.
+     *
+     * @return this
+     */
     public StrBuilder endl() {
         return append(options.peek().endl());
     }
-    
+
+    /**
+     * Appends blank value as configured in options for current block.
+     *
+     * @return this
+     */
     public StrBuilder append() {
         String value = options.peek().blank();
         return null == value ? this : append(value);
@@ -221,11 +420,25 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         }
         return this;
     }
-    
+
+    /**
+     * Appends string into buffer
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(String value) {
         return (value == null) ? append() : append(value, 0, value.length());
     }
-    
+
+    /**
+     * Appends fragment of string into buffer
+     *
+     * @param value value
+     * @param begin begin
+     * @param end end
+     * @return this
+     */
     public StrBuilder append(String value, int begin, int end) {
         if (value == null) {
             return append();
@@ -239,11 +452,25 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         }
         return this;
     }
-    
+
+    /**
+     * Appends StringBuffer into buffer
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(StringBuffer value) {
         return (value == null) ? append() : append(value, 0, value.length());
     }
-    
+
+    /**
+     * Appends fragment of StringBuffer into buffer
+     *
+     * @param value value
+     * @param begin begin
+     * @param end end
+     * @return this
+     */
     public StrBuilder append(StringBuffer value, int begin, int end) {
         if (value == null) {
             return append();
@@ -257,11 +484,25 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         }
         return this;
     }
-    
+
+    /**
+     * Appends StringBuilder into buffer
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(StringBuilder value) {
         return (value == null) ? append() : append(value, 0, value.length());
     }
-    
+
+    /**
+     * Appends fragment of StringBuilder into buffer
+     *
+     * @param value value
+     * @param begin begin
+     * @param end end
+     * @return this
+     */
     public StrBuilder append(StringBuilder value, int begin, int end) {
         if (value == null) {
             return append();
@@ -275,11 +516,25 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         }
         return this;
     }
-    
+
+    /**
+     * Appends chars into buffer
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(char[] value) {
         return (value == null) ? append() : append(value, 0, value.length);
     }
-    
+
+    /**
+     * Appends fragment of chars into buffer
+     *
+     * @param value value
+     * @param begin begin
+     * @param end end
+     * @return this
+     */
     public StrBuilder append(char[] value, int begin, int end) {
         if (value == null) {
             return append();
@@ -301,42 +556,116 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         return this;
     }
 
+    /**
+     * Appends value into buffer.
+     * Converts object using "toString" method.
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(Object value) {
         return (value == null) ? append() : append(value.toString());        
     }
-    
+
+    /**
+     * Appends value into buffer.
+     * Converts boolean to "true" or "false" string
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(boolean value) {
         return append(value ? "true" : "false");
     }
-    
+
+    /**
+     * Appends value into buffer.
+     * Converts value using "String.valueOf"
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(int value) {
         return append(String.valueOf(value));
     }
 
+    /**
+     * Appends value into buffer.
+     * Converts value using "String.valueOf"
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(long value) {
         return append(String.valueOf(value));
     }
 
+    /**
+     * Appends value into buffer.
+     * Converts value using "String.valueOf"
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(float value) {
         return append(String.valueOf(value));
     }
 
+    /**
+     * Appends value into buffer.
+     * Converts value using "String.valueOf"
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilder append(double value) {
         return append(String.valueOf(value));
     }
-    
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "String.valueOf"
+     *
+     * @param values values
+     * @return this
+     */
     public StrBuilder append(Iterable<?> values) {
 		return append(values.iterator(), this::asString);
 	}
-    
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "function"
+     *
+     * @param values values
+     * @param function function
+     * @param <T> T
+     * @return this
+     */
     public <T> StrBuilder append(Iterable<? extends T> values, Function<? super T,String> function) {
 		return append(values.iterator(), function);
 	}
-    
-    public <T> StrBuilder append(Iterator<? extends T> values) {
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "String.valueOf"
+     *
+     * @param values values
+     * @return this
+     */
+    public StrBuilder append(Iterator<?> values) {
         return append(values, this::asString);
     }
-        
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "function"
+     *
+     * @param values values
+     * @param function function
+     * @param <T> T
+     * @return this
+     */
     public <T> StrBuilder append(Iterator<? extends T> values, Function<? super T,String> function) {
         if ( !values.hasNext() ) {
             return this;
@@ -351,7 +680,15 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
             append(separator);
         }
 	}
-    
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "String.valueOf"
+     *
+     * @param values values
+     * @param <T> T
+     * @return this
+     */
     public <T> StrBuilder append(T[] values) {
         return append(values, this::asString);
     }
@@ -359,7 +696,16 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
     private String asString(Object value) {
         return null == value ? null : value.toString();
     }
-    
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "function"
+     *
+     * @param values values
+     * @param function function
+     * @param <T> T
+     * @return this
+     */
     public <T> StrBuilder append(T[] values, Function<? super T,String> function) {
         if ( 0==values.length ) {
             return this;
@@ -371,12 +717,26 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         }
 		return this;
 	}
-    
-    public <T> StrBuilder append(NativeArray values) {
+
+    /**
+     * Appends values into buffer, separating them using "options.separator".
+     * Converts values using "String.valueOf"
+     *
+     * @param values values
+     * @return this
+     */
+    public StrBuilder append(NativeArray values) {
         return append(values.size(), i -> String.valueOf(values.get(i)));
     }
-    
-    public <T> StrBuilder append(int size, IntFunction<String> function) {
+
+    /**
+     * Appends "size" values generated by "function", separating them using "options.separator".
+     *
+     * @param size size
+     * @param function function
+     * @return this
+     */
+    public StrBuilder append(int size, IntFunction<String> function) {
         if ( 0==size ) {
             return this;
         }
@@ -388,6 +748,15 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
 		return this;
 	}
 
+    /**
+     * Replaces characters from specified range by new value.
+     * Shifts all data, if necessary, i.e. value had different length than range.
+     *
+     * @param begin begin
+     * @param end end
+     * @param value value
+     * @return this
+     */
     public StrBuilder replace(int begin, int end, CharSequence value) {
         if(value == null) {
             value = options.peek().blank();
@@ -405,6 +774,15 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         return this;
     }
 
+    /**
+     * Replaces characters from specified range by new value
+     * Shifts all data, if necessary, i.e. value had different length than range.
+     *
+     * @param begin begin
+     * @param end end
+     * @param value value
+     * @return this
+     */
     public StrBuilder replace(int begin, int end, char[] value) {
         if(value == null) {
             return replace(begin, end, options.peek().blank());
@@ -419,12 +797,28 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         return this;
     }
 
+    /**
+     * Inserts value at specified index.
+     * Shifts content already stored in buffer if necessary.
+     *
+     * @param offset offset
+     * @param value value
+     * @return this
+     */
     public StrBuilder insert(int offset, CharSequence value) {
         insertBytes(offset, value.length());
         copy(offset, value, 0, value.length());
         return this;
     }
 
+    /**
+     * Inserts value at specified index.
+     * Shifts content already stored in buffer if necessary.
+     *
+     * @param offset offset
+     * @param value value
+     * @return this
+     */
     public StrBuilder insert(int offset, char[] value) {
         insertBytes(offset, value.length);
         copy(offset, value, 0, value.length);
@@ -461,6 +855,14 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
         return this;
     }
 
+    /**
+     * Appends string generated by {@link Formatter}.
+     * It uses default locale.
+     *
+     * @param format format
+     * @param arguments arguments
+     * @return this
+     */
 	public StrBuilder printf(String format, Object... arguments) {
         formatter.get().format(Locale.getDefault(), format, arguments);
         return this;
@@ -513,15 +915,33 @@ public final class StrBuilder implements CharSequence, Appendable, Serializable
     public String toString() {
         return new String(buffer, 0, size);
     }
-    
+
+    /**
+     * Creates new StringBuilder with buffer content.
+     * StringBuilder capacity is exactly current size.
+     *
+     * @return StringBuilder
+     */
     public StringBuilder toBuilder() {
         return new StringBuilder(size).append(buffer, 0, size);
     }
-    
+
+    /**
+     * Returns new instance of Writer view.
+     * Writer can be used to change buffer and vice versa.
+     *
+     * @return Writer
+     */
     public Writer asWriter() {
         return new SWriter();
     }
-    
+
+    /**
+     * Returns new instance of Reader view.
+     * Changes inside buffer will be visible in Reader.
+     *
+     * @return Reader
+     */
     public Reader asReader() {
         return new SReader();
     }

+ 70 - 1
assira.core/src/main/java/net/ranides/assira/text/StrBuilderOptions.java

@@ -9,10 +9,11 @@ package net.ranides.assira.text;
 import java.io.Serializable;
 
 /**
+ * Base class used by StrBuilder and StrBuilder to store information about internal state and configuration.
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
-public class StrBuilderOptions implements Serializable {
+public abstract class StrBuilderOptions implements Serializable {
     
     private static final long serialVersionUID = 1L;
     
@@ -22,42 +23,110 @@ public class StrBuilderOptions implements Serializable {
         // do nothing
     }
 
+    /**
+     * String value inserted into buffer if inserted value is "null"
+     * It is used by {@link StrBuilder#append()} too.
+     *
+     * If returned String is still null , then buffer does not change its content.
+     *
+     * Default value is: null
+     *
+     * @return String
+     */
     public String blank() {
         return null;
     }
 
+    /**
+     * Changes String value inserted into buffer if inserted value is "null"
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilderOptions blank(String value) {
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * String value used by buffer as line separator.
+     *
+     * Default value is: {@link StringUtils#ENDL}
+     *
+     * @return String
+     */
     public String endl() {
         return StringUtils.ENDL;
     }
 
+    /**
+     * Changes String value used by buffer as line separator.
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilderOptions endl(String value) {
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * String value used as item separator.
+     *
+     * Default value is: ", "
+     *
+     * @return String
+     */
     public String separator() {
         return ", ";
     }
 
+    /**
+     * Changes String value used as item separator.
+     *
+     * @param value value
+     * @return this
+     */
     public StrBuilderOptions separator(String value) {
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * String value inserted before list of items.
+     *
+     * Default value is: null (which means that "blank" will be used)
+     *
+     * @return String
+     */
     public String open() {
         return null;
     }
 
+    /**
+     * Changes String value inserted before list of items.
+     *
+     * @param open open
+     * @return this
+     */
     public StrBuilderOptions open(String open) {
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * String value inserted after list of items.
+     *
+     * Default value is: null (which means that "blank" will be used)
+     *
+     * @return String
+     */
     public String close() {
         return null;
     }
 
+    /**
+     * Changes String value inserted after list of items.
+     *
+     * @param close close
+     * @return this
+     */
     public StrBuilderOptions close(String close) {
         throw new UnsupportedOperationException();
     }

+ 87 - 15
assira.core/src/main/java/net/ranides/assira/text/StringTraits.java

@@ -7,32 +7,67 @@
 
 package net.ranides.assira.text;
 
+import lombok.experimental.UtilityClass;
+
 /**
+ * Null-safe static methods checking string content.
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
+@UtilityClass
 public final class StringTraits {
-    
-    private StringTraits() {
-        /* utility class */
-    }
 
+    /**
+     * Returns true if value is not empty.
+     * That means: it isn't null and contains at least one character.
+     *
+     * @param value value
+     * @return boolean
+     */
     public static boolean isNotEmpty(CharSequence value) {
         return !isEmpty(value);
     }
 
+    /**
+     * Returns true if value is not blank.
+     * That means: it isn't null and contains at least one non-space character.
+     *
+     * @param value value
+     * @return boolean
+     */
     public static boolean isNotBlank(CharSequence value) {
         return !isBlank(value);
     }
-    
+
+    /**
+     * Returns true if value is empty.
+     * That means: it is null or its length is zero.
+     *
+     * @param value value
+     * @return boolean
+     */
     public static boolean isEmpty(CharSequence value) {
 		return null == value || 0 == value.length();
 	}
-	
+
+    /**
+     * Returns true if value is blank.
+     * That means: it is null, its length is zero, or contains only white-space characters.
+     *
+     * @param value value
+     * @return boolean
+     */
 	public static boolean isBlank(CharSequence value) {
 		return isEmpty(value) || value.toString().trim().isEmpty();
 	}
-	
+
+    /**
+     * Returns true if value is decimal number.
+     * That means: it is not empty and contains only decimal digits
+     *
+     * @param text text
+     * @return boolean
+     */
     public static boolean isNumber(CharSequence text) {
         if(isEmpty(text)) {
             return false;
@@ -48,30 +83,67 @@ public final class StringTraits {
     private static boolean isNumber(char c) {
         return c>='0' && c<='9';
     }
-    
+
+    /**
+     * Returns true if text starts with prefix.
+     * That means: text is not null and contains "prefix" at the very begining
+     *
+     * @param text text
+     * @param prefix prefix
+     * @return boolean
+     */
     public static boolean starts(String text, String prefix) {
 		return null != text && text.startsWith(prefix);
 	}
-    
+
+    /**
+     * Returns true if text ends with suffix.
+     * That means: text is not null and contains "suffix" at the very end
+     *
+     * @param text text
+     * @param suffix suffix
+     * @return boolean
+     */
     public static boolean ends(String text, String suffix) {
 		return null != text && text.endsWith(suffix);
 	}
-    
+
+    /**
+     * Returns true if text contains character.
+     *
+     * @param text text
+     * @param ch ch
+     * @return boolean
+     */
     public static boolean contains(String text, int ch) {
         return null != text && -1 != text.indexOf(ch);
     }
-    
+
+    /**
+     * Returns true if text contains specified fragment.
+     *
+     * @param text text
+     * @param fragment fragment
+     * @return boolean
+     */
     public static boolean contains(String text, String fragment) {
 		return null != text && text.contains(fragment);
 	}
 
-    public static boolean isJavaIdentifier(String line) {
-        int cp = line.codePointAt(0);
+    /**
+     * Returns true if text could be used as java identifier.
+     * Valid java identifiers are described in JLS Chapter 3.
+     *
+     * @param text text
+     * @return boolean
+     */
+    public static boolean isJavaIdentifier(String text) {
+        int cp = text.codePointAt(0);
         if (!Character.isJavaIdentifierStart(cp)) {
             return false;
         }
-        for (int i = Character.charCount(cp), n = line.length(); i < n; i += Character.charCount(cp)) {
-            cp = line.codePointAt(i);
+        for (int i = Character.charCount(cp), n = text.length(); i < n; i += Character.charCount(cp)) {
+            cp = text.codePointAt(i);
             if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {
                 return false;
             }

File diff suppressed because it is too large
+ 592 - 71
assira.core/src/main/java/net/ranides/assira/text/StringUtils.java


+ 42 - 4
assira.core/src/main/java/net/ranides/assira/text/Wildcard.java

@@ -12,6 +12,8 @@ import java.util.function.Predicate;
 import java.util.regex.Pattern;
 
 /**
+ * Wildcard class is simple Predicate which accepts CharSequences matching to the pattern.
+ * Pattern consists of standard glob operators: * and ?
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
@@ -24,18 +26,42 @@ public final class Wildcard implements Serializable, Predicate<CharSequence> {
 	private Wildcard(Pattern re) {
 		this.re = re;
 	}
-	
+
+	/**
+	 * Creates new wildcard matching to pattern.
+	 * Supported special characters: * for any text, ? for any char
+	 *
+	 * @param pattern pattern
+	 * @return Wildcard
+	 */
 	public static Wildcard compile(String pattern) {
 		return compile(pattern,0);
 	}
-	
+
+	/**
+	 * Creates new wildcard matching to pattern.
+	 * Supported special characters: * for any text, ? for any char
+	 *
+	 * Accepts flags supported by {@link Pattern}.
+	 *
+	 * @param pattern pattern
+	 * @param flags flags
+	 * @return Wildcard
+	 */
 	public static Wildcard compile(String pattern, int flags) {
         String p = StringUtils.escapeRE(pattern)
             .replace("\\*", ".*")
             .replace("\\?",".");
 		return new Wildcard(Pattern.compile(p, flags));
 	}
-    
+
+	/**
+	 * Returns true if provided pattern matches provided text.
+	 *
+	 * @param pattern pattern
+	 * @param text text
+	 * @return boolean
+	 */
     public static boolean match(String pattern, String text) {
         return compile(pattern).test(text);
     }
@@ -44,11 +70,23 @@ public final class Wildcard implements Serializable, Predicate<CharSequence> {
 	public boolean test(CharSequence text) {
 		return re.matcher(text).matches();
 	}
-	
+
+	/**
+	 * Returns Pattern which is equivalent to this Wildcard.
+	 *
+	 * @return Pattern
+	 */
 	public Pattern asPattern() {
 		return re;
 	}
 
+	/**
+	 * Returns Predicate which tests paths instead of Strings.
+	 *
+	 * Only filename part inside Path is tested against pattern.
+	 *
+	 * @return Predicate
+	 */
 	public Predicate<Path> asPathFilter() {
 		return f -> test(f.getFileName().toString());
 	}

+ 6 - 6
assira.core/src/test/java/net/ranides/assira/text/StrBufferTest.java

@@ -342,13 +342,13 @@ public class StrBufferTest {
     public void testFragmet() {
         StrBuffer sb = new StrBuffer(32).append("Hello world");
         
-        assertEquals("", sb.getLeftFragment(0));
-        assertEquals("Hell", sb.getLeftFragment(4));
-        assertEquals("Hello world", sb.getLeftFragment(60));
+        assertEquals("", sb.getHeadFragment(0));
+        assertEquals("Hell", sb.getHeadFragment(4));
+        assertEquals("Hello world", sb.getHeadFragment(60));
         
-        assertEquals("", sb.getRightFragment(0));
-        assertEquals("orld", sb.getRightFragment(4));
-        assertEquals("Hello world", sb.getRightFragment(60));
+        assertEquals("", sb.getTailFragment(0));
+        assertEquals("orld", sb.getTailFragment(4));
+        assertEquals("Hello world", sb.getTailFragment(60));
     }
     
     @Test

+ 6 - 6
assira.core/src/test/java/net/ranides/assira/text/StrBuilderTest.java

@@ -385,13 +385,13 @@ public class StrBuilderTest {
     public void testFragmet() {
         StrBuilder sb = new StrBuilder(32).append("Hello world");
         
-        assertEquals("", sb.getLeftFragment(0));
-        assertEquals("Hell", sb.getLeftFragment(4));
-        assertEquals("Hello world", sb.getLeftFragment(60));
+        assertEquals("", sb.getHeadFragment(0));
+        assertEquals("Hell", sb.getHeadFragment(4));
+        assertEquals("Hello world", sb.getHeadFragment(60));
         
-        assertEquals("", sb.getRightFragment(0));
-        assertEquals("orld", sb.getRightFragment(4));
-        assertEquals("Hello world", sb.getRightFragment(60));
+        assertEquals("", sb.getTailFragment(0));
+        assertEquals("orld", sb.getTailFragment(4));
+        assertEquals("Hello world", sb.getTailFragment(60));
     }
     
     @Test

+ 8 - 0
assira.core/src/test/java/net/ranides/assira/text/StringUtilsTest.java

@@ -627,6 +627,14 @@ c*/
         assertEquals("hello\nworld\nhere\n", StringUtils.asUnix("hello\r\nworld\rhere\n"));
     }
 
+    @Test
+    public void asWindows() {
+        assertEquals("hello\r\nworld\r\nhere\r\n", StringUtils.asWindows("hello\nworld\nhere\n"));
+        assertEquals("hello\r\nworld\r\nhere\r\n", StringUtils.asWindows("hello\r\nworld\nhere\r\n"));
+        assertEquals("hello\r\nworld\r\n\r\nhere\r\n", StringUtils.asWindows("hello\r\nworld\n\rhere\r\n"));
+        assertEquals("hello\r\nworld\r\nhere\r\n", StringUtils.asWindows("hello\r\nworld\rhere\n"));
+    }
+
     private static void assertLimitEquals(String expected, CharSequence value) {
 	    assertEquals(expected, value.toString());
 	    assertEquals(expected.length(), value.length());