@Override public CharSeq slice(int beginIndex, int endIndex) { final int from = beginIndex < 0 ? 0 : beginIndex; final int to = endIndex > length() ? length() : endIndex; if (from >= to) { return EMPTY; } if (from <= 0 && to >= length()) { return this; } return CharSeq.of(back.substring(from, to)); }
@Override public CharSeq patch(int from, Iterable<? extends Character> that, int replaced) { from = from < 0 ? 0 : from > length() ? length() : from; replaced = replaced < 0 ? 0 : replaced; final StringBuilder sb = new StringBuilder(back.substring(0, from)); for (char character : that) { sb.append(character); } from += replaced; if (from < length()) { sb.append(back.substring(from)); } return sb.length() == 0 ? EMPTY : of(sb); }
@Override public CharSeq subSequence(int beginIndex) { if (beginIndex < 0 || beginIndex > length()) { throw new IndexOutOfBoundsException("begin index " + beginIndex + " < 0"); } if (beginIndex == 0) { return this; } else if (beginIndex == length()) { return EMPTY; } else { return CharSeq.of(back.substring(beginIndex)); } }
@Override public CharSeq insert(int index, Character element) { if (index < 0) { throw new IndexOutOfBoundsException("insert(" + index + ", e)"); } if (index > length()) { throw new IndexOutOfBoundsException("insert(" + index + ", e) on String of length " + length()); } final char c = element; return of(new StringBuilder(back).insert(index, c).toString()); }
@Override public CharSeq drop(int n) { if (n <= 0) { return this; } else if (n >= length()) { return EMPTY; } else { return of(back.substring(n)); } }
@Override public CharSeq take(int n) { if (n <= 0) { return EMPTY; } else if (n >= length()) { return this; } else { return CharSeq.of(back.substring(0, n)); } }
@Override public CharSeq update(int index, Character element) { if ((index < 0) || (index >= length())) { throw new IndexOutOfBoundsException("update(" + index + ")"); } else { char c = element; return of(back.substring(0, index) + c + back.substring(index + 1)); } }
@Override public CharSeq init() { if (isEmpty()) { throw new UnsupportedOperationException("init of empty string"); } else { return of(back.substring(0, length() - 1)); } }
@Override public CharSeq removeLast(Predicate<Character> predicate) { Objects.requireNonNull(predicate, "predicate is null"); for (int i = length() - 1; i >= 0; i--) { if (predicate.test(get(i))) { return removeAt(i); } } return this; }
@Override public Tuple2<CharSeq, CharSeq> span(Predicate<? super Character> predicate) { Objects.requireNonNull(predicate, "predicate is null"); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < length(); i++) { final char c = get(i); if (predicate.test(c)) { sb.append(c); } else { break; } } return splitByBuilder(sb); }
@Override public <U> IndexedSeq<U> map(Function<? super Character, ? extends U> mapper) { Objects.requireNonNull(mapper, "mapper is null"); IndexedSeq<U> result = Vector.empty(); for (int i = 0; i < length(); i++) { result = result.append(mapper.apply(get(i))); } return result; }
@Override public <U> IndexedSeq<U> zipWithIndex(BiFunction<? super Character, ? super Integer, ? extends U> mapper) { Objects.requireNonNull(mapper, "mapper is null"); IndexedSeq<U> result = Vector.empty(); for (int i = 0; i < length(); i++) { result = result.append(mapper.apply(get(i), i)); } return result; }
@Override public CharSeq intersperse(Character element) { final char c = element; // intentionally throw when element is null if (isEmpty()) { return EMPTY; } else { final StringBuilder sb = new StringBuilder().append(head()); for (int i = 1; i < length(); i++) { sb.append(c).append(get(i)); } return of(sb); } }
private Tuple2<CharSeq, CharSeq> splitByBuilder(StringBuilder sb) { if (sb.length() == 0) { return Tuple.of(EMPTY, this); } else if (sb.length() == length()) { return Tuple.of(this, EMPTY); } else { return Tuple.of(of(sb), of(back.substring(sb.length()))); } }
@Override public IndexedSeq<CharSeq> combinations() { return Vector.rangeClosed(0, length()).map(this::combinations).flatMap(Function.identity()); }
@Override public Tuple2<CharSeq, CharSeq> splitAt(int n) { if (n <= 0) { return Tuple.of(EMPTY, this); } else if (n >= length()) { return Tuple.of(this, EMPTY); } else { return Tuple.of(of(back.substring(0, n)), of(back.substring(n))); } }
@Override public <T1, T2> Tuple2<IndexedSeq<T1>, IndexedSeq<T2>> unzip(Function<? super Character, Tuple2<? extends T1, ? extends T2>> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); IndexedSeq<T1> xs = Vector.empty(); IndexedSeq<T2> ys = Vector.empty(); for (int i = 0; i < length(); i++) { final Tuple2<? extends T1, ? extends T2> t = unzipper.apply(get(i)); xs = xs.append(t._1); ys = ys.append(t._2); } return Tuple.of(xs, ys); }
@Override public <T1, T2, T3> Tuple3<IndexedSeq<T1>, IndexedSeq<T2>, IndexedSeq<T3>> unzip3(Function<? super Character, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); IndexedSeq<T1> xs = Vector.empty(); IndexedSeq<T2> ys = Vector.empty(); IndexedSeq<T3> zs = Vector.empty(); for (int i = 0; i < length(); i++) { final Tuple3<? extends T1, ? extends T2, ? extends T3> t = unzipper.apply(get(i)); xs = xs.append(t._1); ys = ys.append(t._2); zs = zs.append(t._3); } return Tuple.of(xs, ys, zs); }