/*
This file is part of Reactive Cascade which is released under The MIT License.
See license.md , https://github.com/futurice/cascade and http://reactivecascade.com for details.
This is open source for the common good. Please contribute improvements by pull request or contact paulirotta@gmail.com
*/
package com.reactivecascade.reactive;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.reactivecascade.i.IActionOne;
import com.reactivecascade.i.IActionOneR;
import com.reactivecascade.i.IThreadType;
import com.reactivecascade.util.AssertUtil;
import com.reactivecascade.util.RCLog;
import java.util.Locale;
/**
* A {@link String} which can be updated with various string operations in an atomic, thread-safe manner.
* <p>
* This is similar to an {@link java.util.concurrent.atomic.AtomicInteger} with reactive bindings to
* get and set the from in reactive chains (function sequences that can fire multiple times).
* <p>
* Created by phou on 30-04-2015.
*/
public class ReactiveString extends ReactiveValue<String> {
/**
* Create a new atomic integer
*
* @param name
* @param initialValue
*/
public ReactiveString(
@NonNull String name,
@Nullable String initialValue) {
super(name, initialValue);
}
/**
* Create a new atomic integer
*
* @param threadType
* @param name
* @param onFireAction a mapping for incoming values, for example <code>i -> Math.max(0, i)</code>
* @param onError action
*/
public ReactiveString(
@NonNull IThreadType threadType,
@NonNull String name,
@Nullable IActionOneR<String, String> onFireAction,
@NonNull IActionOne<Exception> onError) {
super(name, threadType, onFireAction, onError);
}
/**
* Mutates this string by concatenating a string to the end of the current from in a thread-safe manner
*
* @param string to be concatenated
* @return the concatenated result
*/
@CallSuper
public String concat(@NonNull final String string) {
while (true) {
final String currentValue = get();
AssertUtil.assertNotNull("String from not yet asserted", currentValue);
final String concat = currentValue.concat(string);
if (compareAndSet(currentValue, concat)) {
return concat;
}
RCLog.d(this, "Collision in concurrent concat(" + string + "), will try again: " + currentValue);
}
}
/**
* Mutates this string after replacing occurrences of the given {@code char} with another.
*
* @param oldChar to be replaced
* @param newChar replacement from
* @return the replaced mutated from
*/
@CallSuper
public String replace(final char oldChar,
final char newChar) {
while (true) {
final String currentValue = get();
AssertUtil.assertNotNull("String from not yet asserted", currentValue);
final String replace = currentValue.replace(oldChar, newChar);
if (compareAndSet(currentValue, replace)) {
return replace;
}
RCLog.d(this, "Collision in concurrent replace(" + oldChar + ", " + newChar + "), will try again: " + currentValue);
}
}
/**
* Mutates this string after replacing occurrences of the given {@link CharSequence} with another.
*
* @param oldChars to be replaced
* @param newChars replacement from
* @return the replaced mutated from
*/
@CallSuper
public String replace(final CharSequence oldChars,
final CharSequence newChars) {
while (true) {
final String currentValue = get();
AssertUtil.assertNotNull("String from not yet asserted", currentValue);
final String replace = currentValue.replace(oldChars, newChars);
if (compareAndSet(currentValue, replace)) {
return replace;
}
RCLog.d(this, "Collision in concurrent replace(" + oldChars + ", " + newChars + "), will try again: " + currentValue);
}
}
/**
* Mutates this string to lower case, using the rules of {@code locale}.
*
* @param locale for case conversion
* @return the lower case mutated state
*/
@CallSuper
public String toLowerCase(@NonNull final Locale locale) {
while (true) {
final String currentValue = get();
AssertUtil.assertNotNull("String from not yet asserted", currentValue);
final String lowerCase = currentValue.toLowerCase(locale);
if (compareAndSet(currentValue, lowerCase)) {
return lowerCase;
}
RCLog.d(this, "Collision in concurrent toLowerCase(" + locale + "), will try again: " + currentValue);
}
}
}