001package org.clafer.ir;
002
003import gnu.trove.TIntCollection;
004import gnu.trove.iterator.TIntIterator;
005import org.clafer.collection.BoundIntIterator;
006import org.clafer.collection.ReverseBoundIntIterator;
007import org.clafer.collection.SingleIntIterator;
008
009/**
010 * Boolean domain.
011 *
012 * @author jimmy
013 */
014public enum IrBoolDomain implements IrDomain {
015
016    TrueDomain(true, false),
017    FalseDomain(false, true),
018    BoolDomain(true, true);
019    private final boolean hasTrue, hasFalse;
020
021    private IrBoolDomain(boolean hasTrue, boolean hasFalse) {
022        assert hasTrue || hasFalse;
023        // At least one has to be true.
024        this.hasTrue = hasTrue;
025        this.hasFalse = hasFalse;
026    }
027
028    @Override
029    public boolean isBounded() {
030        return true;
031    }
032
033    /**
034     * @param value test this value
035     * @return {@code true} if and only if the domain contains the {@code value},
036     *         {@code false} otherwise
037     */
038    public boolean contains(boolean value) {
039        return value ? hasTrue : hasFalse;
040    }
041
042    @Override
043    public boolean contains(int value) {
044        switch (value) {
045            case 0:
046                return hasFalse;
047            case 1:
048                return hasTrue;
049            default:
050                return false;
051        }
052    }
053
054    @Override
055    public int getLowBound() {
056        return hasFalse ? 0 : 1;
057    }
058
059    @Override
060    public int getHighBound() {
061        return hasTrue ? 1 : 0;
062    }
063
064    @Override
065    public boolean isEmpty() {
066        return false;
067    }
068
069    @Override
070    public int size() {
071        return hasTrue && hasFalse ? 2 : 1;
072    }
073
074    /**
075     * Reverse the domain. Maps {0}->{1}, {1}->{0}, and {0,1}->{0,1}.
076     *
077     * @return the inverted domain
078     */
079    public IrBoolDomain invert() {
080        switch (this) {
081            case TrueDomain:
082                return FalseDomain;
083            case FalseDomain:
084                return TrueDomain;
085            case BoolDomain:
086                return BoolDomain;
087            default:
088                throw new IllegalStateException();
089        }
090    }
091
092    @Override
093    public int[] getValues() {
094        switch (this) {
095            case TrueDomain:
096                return new int[]{1};
097            case FalseDomain:
098                return new int[]{0};
099            case BoolDomain:
100                return new int[]{0, 1};
101            default:
102                throw new IllegalStateException();
103        }
104    }
105
106    @Override
107    public TIntIterator iterator() {
108        return iterator(true);
109    }
110
111    @Override
112    public TIntIterator iterator(boolean increasing) {
113        switch (this) {
114            case TrueDomain:
115                return new SingleIntIterator(1);
116            case FalseDomain:
117                return new SingleIntIterator(0);
118            case BoolDomain:
119                return increasing ? new BoundIntIterator(0, 1) : new ReverseBoundIntIterator(0, 1);
120            default:
121                throw new IllegalStateException();
122        }
123    }
124
125    @Override
126    public void transferTo(TIntCollection collection) {
127        if (hasTrue) {
128            collection.add(1);
129        }
130        if (hasFalse) {
131            collection.add(0);
132        }
133    }
134
135    @Override
136    public String toString() {
137        switch (this) {
138            case TrueDomain:
139                return "{1}";
140            case FalseDomain:
141                return "{0}";
142            case BoolDomain:
143                return "{0,1}";
144            default:
145                throw new IllegalStateException();
146        }
147    }
148}