/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.flink.graph.utils.proxy;
import org.apache.flink.graph.GraphAlgorithm;
/**
* A multi-state boolean.
* <p>
* This class is used by {@link GraphAlgorithm} configuration options to set a
* default value which can be overwritten. The default value is also used when
* algorithm configurations are merged and conflict.
*/
public class OptionalBoolean {
protected enum State {
UNSET,
FALSE,
TRUE,
CONFLICTING
}
private State state = State.UNSET;
private final boolean valueIfUnset;
private final boolean valueIfConflicting;
/**
* An {@code OptionalBoolean} has three possible states: true, false, and
* "unset". The value is set when merged with a value of true or false. The
* state returns to unset either explicitly or when true is merged with false.
*
* @param valueIfUnset the value to return when the object's state is unset
* @param valueIfConflicting the value to return when the object's state is conflicting
*/
public OptionalBoolean(boolean valueIfUnset, boolean valueIfConflicting) {
this.valueIfUnset = valueIfUnset;
this.valueIfConflicting = valueIfConflicting;
}
/**
* Get the boolean state.
*
* @return boolean state
*/
public boolean get() {
switch (state) {
case UNSET:
return valueIfUnset;
case FALSE:
return false;
case TRUE:
return true;
case CONFLICTING:
return valueIfConflicting;
default:
throw new RuntimeException("Unknown state");
}
}
/**
* Set the boolean state.
*
* @param value boolean state
*/
public void set(boolean value) {
this.state = (value ? State.TRUE : State.FALSE);
}
/**
* Reset to the unset state.
*/
public void unset() {
this.state = State.UNSET;
}
/**
* Get the actual state.
*
* @return actual state
*/
protected State getState() {
return state;
}
/**
* The conflicting states are true with false and false with true.
*
* @param other object to test with
* @return whether the objects conflict
*/
public boolean conflictsWith(OptionalBoolean other) {
return state == State.CONFLICTING
|| other.state == State.CONFLICTING
|| (state == State.TRUE && other.state == State.FALSE)
|| (state == State.FALSE && other.state == State.TRUE);
}
/**
* State transitions:
* if the states are the same then no change
* if either state is unset then change to the other state
* if the states are conflicting then set to the conflicting state
*
* @param other object from which to merge state
*/
public void mergeWith(OptionalBoolean other) {
if (state == other.state) {
// no change in state
} else if (state == State.UNSET) {
state = other.state;
} else if (other.state == State.UNSET) {
// no change in state
} else {
state = State.CONFLICTING;
}
}
}