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

net.automatalib.words.WordBuilder Maven / Gradle / Ivy

Go to download

This artifact contains the API of AutomataLib, which mainly consists of interfaces for the various concepts and automaton models supported by the AutomataLib core. In addition to that, it also defines some fundamental classes for dealing with words of symbols.

There is a newer version: 0.11.0
Show newest version
/* Copyright (C) 2013 TU Dortmund
 * This file is part of AutomataLib, http://www.automatalib.net/.
 * 
 * AutomataLib is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 3.0 as published by the Free Software Foundation.
 * 
 * AutomataLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with AutomataLib; if not, see
 * http://www.gnu.de/documents/lgpl.en.html.
 */
package net.automatalib.words;

import java.util.AbstractList;
import java.util.List;

import net.automatalib.commons.util.array.ResizingObjectArray;

/**
 * A class for dynamically building {@link Word}s.
 * 
 * As {@link Word}s are - like strings - immutable objects, constructing them by subsequent
 * invocations of {@link Word#concat(Word...)} etc. is highly inefficient. This class provides an
 * efficient means of construction by operating on an internal storage during construction,
 * only creating a {@link Word} (and thus requiring to ensure immutability) when the method {@link #toWord()}
 * (or {@link #toWord(int, int)} is invoked.
 * 
 * Note that due to the specifics of the underlying word implementation, even after an invocation
 * of {@link #toWord()} the storage does not have to be duplicated unless it either is required
 * due to capacity adjustment or a non-appending change (such as {@link #setSymbol(int, Object)}
 * or {@link #truncate(int)}) is made.
 * 
 * Nearly all modification methods of this class return a this-reference, allowing constructs
 * such as
 * 
builder.append(foo).append(bar).append(baz);
* * @author Malte Isberner * * @param symbol class. */ public final class WordBuilder extends AbstractList { private final ResizingObjectArray storage; private Object[] array; private int length; private boolean lock = false; /** * Constructor. Initializes the builder with a default capacity. */ public WordBuilder() { this.storage = new ResizingObjectArray(); this.array = this.storage.array; } /** * Constructor. Initializes the builder with the specified initial capacity. * @param initialCapacity the initial capacity of the internal storage. */ public WordBuilder(int initialCapacity) { this.storage = new ResizingObjectArray(initialCapacity); this.array = this.storage.array; } /** * Constructor. Initializes the builder with a sequence of count * times the specified symbol. Note that this constructor runs in constant time * if initSym is null. * * @param initSym the initial symbol * @param count the initial symbol count */ public WordBuilder(I initSym, int count) { this.storage = new ResizingObjectArray(count); this.array = this.storage.array; if(initSym != null) { for(int i = 0; i < count; i++) array[i] = initSym; } length = count; } /** * Constructor. Initializes the builder with a sequence of count * times the specified symbol, while allocating the specified initial capacity. * @param capacity the initial capacity of the internal storage. * @param initSym the initial symbol * @param count the initial symbol count */ public WordBuilder(int capacity, I initSym, int count) { if(capacity < count) capacity = count; this.storage = new ResizingObjectArray(capacity); this.array = this.storage.array; if(initSym != null) { for(int i = 0; i < count; i++) array[i] = initSym; } length = count; } /** * Constructor. Initializes the builder with a given word. * @param init the word to initialize the builder with. */ public WordBuilder(Word init) { int wLen = init.length(); this.storage = new ResizingObjectArray(wLen); this.array = this.storage.array; init.writeToArray(0, array, 0, wLen); length = wLen; } /** * Constructor. Initializes the builder with a given word, while allocating * the specified initial capacity. * @param capacity the initial capacity to use. * @param init the initial word */ public WordBuilder(int capacity, Word init) { int wLen = init.length(); if(capacity < wLen) capacity = wLen; this.storage = new ResizingObjectArray(capacity); this.array = this.storage.array; init.writeToArray(0, array, 0, wLen); length = wLen; } public WordBuilder append(List symList) { int lLen = symList.size(); ensureAdditionalCapacity(lLen); for(I sym : symList) array[length++] = sym; return this; } /** * Appends a word to the contents of the internal storage. * @param word the word to append. * @return this */ public WordBuilder append(Word word) { int wLen = word.length(); ensureAdditionalCapacity(wLen); word.writeToArray(0, array, length, wLen); length += wLen; return this; } /** * Appends several words to the contents of the internal storage. * @param words the words to append * @return this */ @SafeVarargs public final WordBuilder append(Word ...words) { if(words.length == 0) return this; int allLen = 0; for(int i = 0; i < words.length; i++) allLen += words[i].length(); ensureAdditionalCapacity(allLen); for(int i = 0; i < words.length; i++) { Word word = words[i]; int wLen = word.length(); word.writeToArray(0, array, length, wLen); length += wLen; } return this; } /** * Appends num copies of the given word to the contents * of the initial storage. * @param num the number of copies * @param word the word * @return this */ public WordBuilder repeatAppend(int num, Word word) { if(num == 0) return this; int wLen = word.length(); int allLen = wLen * num; ensureAdditionalCapacity(allLen); while(num-- > 0) { word.writeToArray(0, array, length, wLen); length += wLen; } return this; } /** * Appends a symbol to the contents of the internal storage. * @param symbol the symbol to append * @return this */ public WordBuilder append(I symbol) { ensureAdditionalCapacity(1); array[length++] = symbol; return this; } /** * Appends num copies of a symbol to the contents of the * internal storage. * @param num the number of copies * @param symbol the symbol * @return this */ public WordBuilder repeatAppend(int num, I symbol) { if(num == 0) return this; ensureAdditionalCapacity(num); if(symbol == null) length += num; else { while(num-- > 0) array[length++] = symbol; } return this; } /** * Appends several symbols to the contents of the internal storage. * @param symbols the symbols to append * @return this */ @SafeVarargs public final WordBuilder append(I ...symbols) { if(symbols.length == 0) return this; ensureAdditionalCapacity(symbols.length); System.arraycopy(symbols, 0, array, length, symbols.length); length += symbols.length; return this; } /** * Ensures that the internal storage has in total the given capacity * @param cap the minimum capacity to ensure */ public void ensureCapacity(int cap) { if(storage.ensureCapacity(cap)) { lock = false; array = storage.array; } } /** * Ensures that the internal storage has additionally the given * capacity. * @param add the additional capacity to ensure */ public void ensureAdditionalCapacity(int add) { ensureCapacity(length + add); } /* * Ensure that non-appending modifications may be made */ private final void ensureUnlocked() { if(lock) { array = array.clone(); storage.array = array; lock = false; } } /** * Retrieves the symbol at the given index * @param index the index to retrieve * @return the symbol at the given index */ @SuppressWarnings("unchecked") public I getSymbol(int index) { return (I)array[index]; } /** * Sets the symbol at the given index. Note that this index must exist. * @param index the index to manipulate * @param symbol the symbol to set * @return this */ public WordBuilder setSymbol(int index, I symbol) { ensureUnlocked(); array[index] = symbol; return this; } /** * Truncates the contents of the initial storage to the given length. * @param truncLen the length to truncate to * @return this */ public WordBuilder truncate(int truncLen) { if(truncLen >= length) return this; ensureUnlocked(); for(int i = truncLen; i < length; i++) array[i] = null; length = truncLen; return this; } /** * Creates a word from the given range of the contents of the internal storage. * Note that the storage management mechanisms of this class guarantee that * the returned word will not change regardless of what further operations are invoked * on this {@link WordBuilder}. * @param fromIndex the starting index * @param toIndex the end index * @return the word for the specified subrange */ public Word toWord(int fromIndex, int toIndex) { if(fromIndex < 0 || toIndex > length) throw new IndexOutOfBoundsException(); int len = toIndex - fromIndex; lock = true; return new SharedWord<>(array, fromIndex, len); } /** * Creates a word from the contents of the internal storage. * Note that the storage management mechanisms of this class guarantee that * the returned word will not change regardless of what further operations are performed * on this {@link WordBuilder}. * @return the internal contents as a word */ public Word toWord() { lock = true; return new SharedWord<>(array, 0, length); } /* * (non-Javadoc) * @see java.util.AbstractList#add(java.lang.Object) */ @Override public boolean add(I e) { append(e); return true; } /* * (non-Javadoc) * @see java.util.AbstractList#get(int) */ @Override public I get(int index) { return getSymbol(index); } /* * (non-Javadoc) * @see java.util.AbstractList#set(int, java.lang.Object) */ @Override public I set(int index, I element) { I old = getSymbol(index); setSymbol(index, element); return old; } /* * (non-Javadoc) * @see java.util.AbstractList#clear() */ @Override public void clear() { ensureUnlocked(); for(int i = 0; i < length; i++) array[i] = null; length = 0; } /* * (non-Javadoc) * @see java.util.AbstractCollection#size() */ @Override public int size() { return length; } public WordBuilder reverse() { ensureUnlocked(); int lowIdx = 0, highIdx = length - 1; while(lowIdx < highIdx) { Object tmp = array[lowIdx]; array[lowIdx++] = array[highIdx]; array[highIdx--] = tmp; } return this; } }