All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dua3.utility.text.RichTextJoiner Maven / Gradle / Ivy

There is a newer version: 15.0.2
Show newest version
package com.dua3.utility.text;

import com.dua3.utility.data.Pair;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * A Joiner for {@link RichText} to be used with {@link java.util.stream.Stream#collect(Collector)}.
 */
public class RichTextJoiner implements Collector, AtomicInteger>, RichText> {

    final Consumer appendDelimiter;
    final Consumer appendPrefix;
    final Consumer appendSuffix;
    final IntUnaryOperator calculateSupplementaryLength;

    /**
     * Creates a RichTextJoiner instance with the given delimiter, prefix, and suffix.
     *
     * @param delimiter the CharSequence used to separate the joined elements
     * @param prefix    the CharSequence to be prepended to the joined elements
     * @param suffix    the CharSequence to be appended to the joined elements
     */
    public RichTextJoiner(CharSequence delimiter,
                          CharSequence prefix,
                          CharSequence suffix) {
        this.appendDelimiter = rtb -> rtb.append(delimiter);
        this.appendPrefix = rtb -> rtb.append(prefix);
        this.appendSuffix = rtb -> rtb.append(suffix);
        this.calculateSupplementaryLength = n -> prefix.length() + n * delimiter.length() + suffix.length();
    }

    /**
     * Creates a RichTextJoiner instance with the given delimiter.
     *
     * @param delimiter the CharSequence used to separate the joined elements
     */
    public RichTextJoiner(CharSequence delimiter) {
        this(delimiter, "", "");
    }

    /**
     * Creates a RichTextJoiner instance with the given delimiter, prefix, and suffix.
     *
     * @param delimiter the RichText used to separate the joined elements
     * @param prefix the RichText added before the joined elements
     * @param suffix the RichText added after the joined elements
     */
    public RichTextJoiner(RichText delimiter,
                          RichText prefix,
                          RichText suffix) {
        this.appendDelimiter = rtb -> rtb.append(delimiter);
        this.appendPrefix = rtb -> rtb.append(prefix);
        this.appendSuffix = rtb -> rtb.append(suffix);
        this.calculateSupplementaryLength = n -> prefix.length() + n * delimiter.length() + suffix.length();
    }

    /**
     * Creates a RichTextJoiner instance with the given delimiter.
     *
     * @param delimiter the RichText used to separate the joined elements
     */
    public RichTextJoiner(RichText delimiter) {
        this(delimiter, RichText.emptyText(), RichText.emptyText());
    }

    @Override
    public Supplier, AtomicInteger>> supplier() {
        return () -> Pair.of(new ArrayList<>(), new AtomicInteger());
    }

    @Override
    public BiConsumer, AtomicInteger>, RichText> accumulator() {
        return (accu, text) -> {
            accu.first().add(text);
            accu.second().addAndGet(text.length());
        };
    }

    @Override
    public BinaryOperator, AtomicInteger>> combiner() {
        return (a, b) -> {
            a.first().addAll(b.first());
            a.second().addAndGet(b.second().get());
            return a;
        };
    }

    @Override
    public Function, AtomicInteger>, RichText> finisher() {
        return accu -> {
            int length = accu.second().get();

            if (length == 0) {
                return RichText.emptyText();
            }

            // calculate needed text length and create builder with sufficient capacity
            int n = accu.first().size();
            int supplementaryLength = calculateSupplementaryLength.applyAsInt(n);
            int totalLength = length + supplementaryLength;
            RichTextBuilder rtb = new RichTextBuilder(totalLength);

            // append prefix and first item
            appendPrefix.accept(rtb);
            rtb.append(accu.first().get(0));

            // append remaining items separated by delimiter
            List first = accu.first();
            for (int i = 1, firstSize = first.size(); i < firstSize; i++) {
                appendDelimiter.accept(rtb);
                rtb.append(first.get(i));
            }

            // append suffix
            appendSuffix.accept(rtb);

            return rtb.toRichText();
        };
    }

    @Override
    public Set characteristics() {
        return Collections.emptySet();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy