org.jenetics.util.CharSeq Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jenetics Show documentation
Show all versions of jenetics Show documentation
Jenetics - Java Genetic Algorithm Library
/*
* Java Genetic Algorithm Library (jenetics-3.8.0).
* Copyright (c) 2007-2017 Franz Wilhelmstötter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author:
* Franz Wilhelmstötter ([email protected])
*/
package org.jenetics.util;
import static java.util.Objects.requireNonNull;
import static org.jenetics.internal.util.Equality.eq;
import java.io.Serializable;
import java.util.Arrays;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collector;
import org.jenetics.internal.collection.Array;
import org.jenetics.internal.collection.ArrayISeq;
import org.jenetics.internal.collection.CharStore;
import org.jenetics.internal.util.Equality;
import org.jenetics.internal.util.Hash;
/**
* This class is used for holding the valid characters of an
* {@link org.jenetics.CharacterGene}. It is not a character sequence in the
* classical sense. The characters of this sequence are sorted and doesn't
* contain duplicate values, like a set.
*
* {@code
* final CharSeq cs1 = new CharSeq("abcdeaafg");
* final CharSeq cs2 = new CharSeq("gfedcbabb");
* assert(cs1.equals(cs2));
* }
*
* @author Franz Wilhelmstötter
* @since 1.0
* @version 2.0
*/
public final class CharSeq
extends CharSeqBase
implements
CharSequence,
ISeq,
Comparable,
Serializable
{
private static final long serialVersionUID = 2L;
/**
* Create a new (distinct) CharSeq from the given {@code characters}. The
* given {@link CharSequence} is sorted and duplicate values are removed
*
* @see #CharSeq(CharSequence)
*
* @param characters the characters.
* @throws NullPointerException if the {@code characters} are {@code null}.
*/
public CharSeq(final char[] characters) {
super(distinct(characters.clone()));
}
/**
* Create a new (distinct) CharSeq from the given {@code characters}. The
* given {@link CharSequence} is sorted and duplicate values are removed.
*
* @param characters the characters.
* @throws NullPointerException if the {@code characters} are {@code null}.
*/
public CharSeq(final CharSequence characters) {
super(distinct(toCharArray(characters)));
}
private static char[] toCharArray(final CharSequence characters) {
requireNonNull(characters, "Characters");
final char[] chars = new char[characters.length()];
for (int i = chars.length; --i >= 0;) {
chars[i] = characters.charAt(i);
}
return chars;
}
private static char[] distinct(final char[] chars) {
Arrays.sort(chars);
int j = 0;
for (int i = 1; i < chars.length; ++i) {
if (chars[j] != chars[i]) {
chars[++j] = chars[i];
}
}
final int size = Math.min(chars.length, j + 1);
final char[] array = new char[size];
System.arraycopy(chars, 0, array, 0, size);
return array;
}
@Override
public boolean contains(final Object object) {
return object instanceof Character && contains((Character)object);
}
/**
* Test whether this character set contains the given character {@code c}.
*
* @param c the character to test.
* @return {@code true} if this character set contains the given character,
* {@code false} otherwise.
* @throws NullPointerException if the given character {@code c} is
* {@code null}.
*/
public boolean contains(final Character c) {
return contains(c.charValue());
}
/**
* Test whether this character set contains the given character {@code c}.
*
* @param c the character to test.
* @return {@code true} if this character set contains the given character,
* {@code false} otherwise.
*/
public boolean contains(final char c) {
return Arrays.binarySearch(array, c) >= 0;
}
@Override
public char charAt(final int index) {
return array[index];
}
@Override
public int length() {
return array.length;
}
@Override
public CharSeq subSequence(final int start, final int end) {
return new CharSeq(new String(array, start, end - start));
}
/**
* Test whether this character set is empty.
*
* @return {@code true} if this character set is empty, {@code false}
* otherwise.
*/
public boolean isEmpty() {
return array.length == 0;
}
@Override
public int hashCode() {
return Hash.of(getClass()).and(array).value();
}
@Override
public boolean equals(final Object obj) {
return Equality.of(this, obj).test(ch ->
eq(array, ch.array)
);
}
@Override
public int compareTo(final CharSeq set) {
int result = 0;
final int n = Math.min(array.length, set.array.length);
for (int i = 0; i < n && result == 0; ++i) {
result = array[i] - set.array[i];
}
if (result == 0) {
result = array.length - set.array.length;
}
return result;
}
@Override
public String toString() {
return new String(array);
}
/**
* Expands the character range for the given {@code pattern}. E.g
* {@code a-zA-Z0-1} will return a string containing all upper and lower
* case characters (from a to z) and all digits form 0 to 9.
*
* @param pattern the {@code pattern} to expand.
* @return the expanded pattern.
* @throws PatternSyntaxException if the pattern could not be expanded.
* @throws NullPointerException if the pattern is {@code null}.
*/
public static String expand(final CharSequence pattern) {
requireNonNull(pattern, "Pattern");
final StringBuilder out = new StringBuilder();
for (int i = 0, n = pattern.length(); i < n; ++i) {
if (pattern.charAt(i) == '\\') {
++i;
if (i < pattern.length()) {
out.append(pattern.charAt(i));
}
} else if (pattern.charAt(i) == '-') {
if (i <= 0 || i >= (pattern.length() - 1)) {
throw new PatternSyntaxException(
"Dangling range operator '-'", pattern.toString(),
pattern.length() - 1
);
}
final String range = expand(
pattern.charAt(i - 1),
pattern.charAt(i + 1)
);
out.append(range);
++i;
} else if (i + 1 == n || pattern.charAt(i + 1) != '-') {
out.append(pattern.charAt(i));
}
}
return out.toString();
}
/**
* Expands the characters between {@code a} and {@code b}.
*
* @param a the start character.
* @param b the stop character.
* @return the expanded characters.
*/
public static String expand(final char a, final char b) {
final StringBuilder out = new StringBuilder();
if (a < b) {
char c = a;
while (c <= b) {
out.append(c);
c = (char) (c + 1);
}
} else if (a > b) {
char c = a;
while (c >= b) {
out.append(c);
c = (char)(c - 1);
}
}
return out.toString();
}
/**
* Expands the character range for the given {@code pattern}. E.g.
* {@code a-zA-Z0-1} will return a string containing all upper and lower
* case characters (from a to z) and all digits form 0 to 9.
*
* @see #expand(CharSequence)
*
* @param pattern the {@code pattern} to expand.
* @return the expanded pattern.
* @throws PatternSyntaxException if the pattern could not be expanded.
* @throws NullPointerException if the pattern is {@code null}.
*/
public static CharSeq of(final CharSequence pattern) {
return new CharSeq(expand(pattern));
}
/**
* Expands the characters between {@code a} and {@code b}.
*
* @see #expand(char, char)
*
* @param a the start character.
* @param b the stop character.
* @return the expanded characters.
*/
public static CharSeq of(final char a, final char b) {
return new CharSeq(expand(a, b));
}
/**
* Helper method for creating a sequence of characters from the given
* {@code CharSequence}. The returned sequence will contain all characters
* in the original order.
*
* @param chars the char sequence to convert.
* @return a sequence which will contain all given chars in the original
* order.
*/
public static ISeq toISeq(final CharSequence chars) {
final MSeq seq = MSeq.ofLength(chars.length());
for (int i = 0; i < chars.length(); ++i) {
seq.set(i, chars.charAt(i));
}
return seq.toISeq();
}
public static Collector toCharSeq() {
return Collector.of(
StringBuilder::new,
StringBuilder::append,
(a, b) -> {a.append(b); return a;},
CharSeq::new
);
}
}
abstract class CharSeqBase extends ArrayISeq {
private static final long serialVersionUID = 1L;
final char[] array;
protected CharSeqBase(final char[] characters) {
super(Array.of(CharStore.of(characters)).seal());
array = characters;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy