001/**
002 * AbstractModuloIntegerPrimitive.java
003 *
004 * Copyright (c) 2004-2012, Nicole C. Tedesco.  All rights reserved.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at:
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package net.sf.jaccumulator.integers;
020
021import java.math.BigDecimal;
022import java.math.BigInteger;
023
024import net.sf.jaccumulator.Domain;
025import net.sf.jaccumulator.StructureStrategy;
026import net.sf.jaccumulator.primitives.Primitive;
027import net.sf.jaccumulator.scalars.Scalar;
028
029/**
030 * Common behavior for all {@link IntegerPrimitive integer} primitives that
031 * obey modular arithmetic
032 *
033 * @param <PRIMITIVE>
034 *        this primitive type (used to facilitate operation chaining on write
035 *        operations)
036 * @since JAccumulator 4.0
037 * @author Nicole Tedesco (<a
038 *         href="mailto:Nicole@NicoleTedesco.com">Nicole@NicoleTedesco.com</a>)
039 */
040public abstract class AbstractModuloIntegerPrimitive<PRIMITIVE extends Primitive<PRIMITIVE>>
041    extends
042        AbstractIntegerPrimitive<PRIMITIVE>
043{
044    private static final long serialVersionUID = 5553304082651635872L;
045
046    private final boolean           _isEmpty;
047    private final boolean           _isOrdered;
048    private final BigInteger        _theBIModularLimit;
049    private final int               _theMaximumValue;
050    private final int               _theModularLimit;
051    private final StructureStrategy _theStrategy;
052
053    public AbstractModuloIntegerPrimitive()
054    {
055        this(0);
056    }
057
058    public <E extends Enum<E>> AbstractModuloIntegerPrimitive( final Class<E> anEnumerationClass )
059    {
060        this( anEnumerationClass.getEnumConstants() );
061    }
062
063    public AbstractModuloIntegerPrimitive( final Enum<?> anEnumeration )
064    {
065        this( anEnumeration.getDeclaringClass().getEnumConstants() );
066    }
067
068    public AbstractModuloIntegerPrimitive( final Enum<?>[] values )
069    {
070        this( values.length );
071    }
072
073    public AbstractModuloIntegerPrimitive( final int aLimit )
074    {
075        super( Domain.MODULO );
076        if ( aLimit < 0 ) {
077            throw new IllegalArgumentException( "The modular limit cannot be less than zero" );
078        }
079        this._theModularLimit = aLimit;
080        this._theBIModularLimit = BigInteger.valueOf(aLimit);
081        switch( aLimit ) {
082        case 0:
083            this._theStrategy = StructureStrategy.EMPTY;
084            break;
085        default:
086            this._theStrategy = StructureStrategy.TUPLE;
087            break;
088        }
089        this._isEmpty = aLimit < 1;
090        this._isOrdered = aLimit == 1;
091        this._theMaximumValue = aLimit - 1;
092    }
093
094    protected final int modulo( final int aValue ) {
095        final int aModularLimit = this.getModularLimit();
096        final int anIndex = aValue % aModularLimit;
097        if (anIndex < 0) {
098            return aModularLimit + anIndex;
099        }
100        return anIndex;
101    }
102
103    @Override
104    @SuppressWarnings( "unchecked" )
105    public final PRIMITIVE absoluteValue()
106        throws UnsupportedOperationException,
107            ArithmeticException,
108            IllegalArgumentException
109    {
110        return (PRIMITIVE)this;
111    }
112
113    @Override
114    public final PRIMITIVE and( final int aValue )
115        throws UnsupportedOperationException,
116            IllegalArgumentException,
117            ArithmeticException
118    {
119        final int result = this.intValue() & aValue;
120        return this.setScalar(result);
121    }
122
123    @Override
124    public final PRIMITIVE decrement()
125        throws UnsupportedOperationException,
126            IllegalArgumentException,
127            ArithmeticException
128    {
129        final int result = this.intValue() - 1;
130        return this.setScalar(result);
131    }
132
133    @Override
134    public final PRIMITIVE difference( final int aValue )
135        throws UnsupportedOperationException,
136            IllegalArgumentException,
137            ArithmeticException
138    {
139        final int result = this.intValue() - aValue;
140        return this.setScalar(result);
141    }
142
143    public final int getMaximumValue() {
144        return this._theMaximumValue;
145    }
146
147    public final int getModularLimit() {
148        return this._theModularLimit;
149    }
150
151    @Override
152    public StructureStrategy getStructureStrategy() {
153        return this._theStrategy;
154    }
155
156    @Override
157    public final PRIMITIVE increment()
158        throws UnsupportedOperationException,
159            ArithmeticException,
160            IllegalArgumentException
161    {
162        final int result = this.intValue() + 1;
163        return this.setScalar(result);
164    }
165
166    @Override
167    @SuppressWarnings( "unchecked" )
168    public final <S extends Scalar<?>> S induceScalarMaximum( final S aTarget ) {
169        return (S)aTarget.setScalar( this.getMaximumValue() );
170    }
171
172    @Override
173    @SuppressWarnings( "unchecked" )
174    public final <S extends Scalar<?>> S induceScalarMinimum( final S aTarget ) {
175        return (S)aTarget.setZero();
176    }
177
178    @Override
179    public final int intPostDecrement()
180        throws UnsupportedOperationException,
181            ArithmeticException,
182            IllegalArgumentException
183    {
184        final int myValue = this.intValue();
185        this.decrement();
186        return myValue;
187    }
188
189    @Override
190    public final int intPostIncrement()
191        throws UnsupportedOperationException,
192            ArithmeticException,
193            IllegalArgumentException
194    {
195        final int myValue = this.intValue();
196        this.increment();
197        return myValue;
198    }
199
200    @Override
201    public final PRIMITIVE inverse()
202        throws UnsupportedOperationException,
203            ArithmeticException,
204            IllegalArgumentException
205    {
206        final int aModularLimit = this.getModularLimit();
207        final int result = intModularInverse( this.intValue(), aModularLimit );
208        return this.setScalar(result);
209    }
210
211    @Override
212    public final boolean isEmpty() {
213        return this._isEmpty;
214    }
215
216    @Override
217    public final boolean isModulo() {
218        return true;
219    }
220
221    @Override
222    public final boolean isOrdered() {
223        return this._isOrdered;
224    }
225
226    @Override
227    public final PRIMITIVE mod( final int aValue )
228        throws UnsupportedOperationException,
229            IllegalArgumentException,
230            ArithmeticException
231    {
232        final int result = this.intValue() % aValue;
233        return this.setScalar(result);
234    }
235
236    @Override
237    public final PRIMITIVE not()
238        throws UnsupportedOperationException,
239            IllegalArgumentException,
240            ArithmeticException
241    {
242        final int result = this.intValue() ^ -1;
243        return this.setScalar(result);
244    }
245
246    @Override
247    public final PRIMITIVE or( final int aValue )
248        throws UnsupportedOperationException,
249            IllegalArgumentException,
250            ArithmeticException
251    {
252        final int result = this.intValue() - aValue;
253        return this.setScalar(result);
254    }
255
256    @Override
257    public final PRIMITIVE product( final int aValue )
258        throws UnsupportedOperationException,
259            IllegalArgumentException,
260            ArithmeticException
261    {
262        final int result = this.intValue() * aValue;
263        return this.setScalar(result);
264    }
265
266    @Override
267    public final PRIMITIVE quotient( final int aValue )
268        throws UnsupportedOperationException,
269            IllegalArgumentException,
270            ArithmeticException
271    {
272        final int result =
273            intModularQuotient(
274                this.intValue(),
275                aValue,
276                this.getModularLimit());
277        return this.setScalar(result);
278    }
279
280    @Override
281    public final PRIMITIVE setMaximum()
282        throws UnsupportedOperationException,
283            ArithmeticException,
284            IllegalArgumentException
285    {
286        return this.setScalar( this.getMaximumValue() );
287    }
288
289    @Override
290    public final PRIMITIVE setMinimum()
291        throws UnsupportedOperationException,
292            ArithmeticException,
293            IllegalArgumentException
294    {
295        return this.setZero();
296    }
297
298    @Override
299    public final PRIMITIVE setReal( final BigDecimal aValue )
300        throws UnsupportedOperationException,
301            IllegalArgumentException,
302            ArithmeticException,
303            NullPointerException
304    {
305        return this.setReal(aValue.toBigInteger());
306    }
307
308    @Override
309    public final PRIMITIVE setReal( final BigInteger aValue )
310        throws UnsupportedOperationException,
311            IllegalArgumentException,
312            ArithmeticException,
313            NullPointerException
314    {
315        return this.setScalar(aValue.mod(this._theBIModularLimit).intValue());
316    }
317
318    @Override
319    public final PRIMITIVE setScalar( final double aValue )
320        throws UnsupportedOperationException,
321            IllegalArgumentException,
322            ArithmeticException
323    {
324        return this.setReal( new BigDecimal( String.valueOf(aValue)) );
325    }
326
327    @Override
328    public final PRIMITIVE setScalar( final float aValue )
329        throws UnsupportedOperationException,
330            IllegalArgumentException,
331            ArithmeticException
332    {
333        return this.setReal( new BigDecimal( String.valueOf(aValue)) );
334    }
335
336    @Override
337    public final PRIMITIVE setScalar( final long aValue )
338        throws UnsupportedOperationException,
339            IllegalArgumentException,
340            ArithmeticException
341    {
342        final long aResult = aValue % this.getModularLimit();
343        return this.setScalar((int)aResult);
344    }
345
346    @Override
347    public PRIMITIVE shiftLeft( final int count )
348        throws UnsupportedOperationException,
349            IllegalArgumentException,
350            ArithmeticException
351    {
352        int myValue = this.intValue();
353        myValue <<= count;
354        return this.setScalar( myValue );
355    }
356
357    @Override
358    public PRIMITIVE shiftRight( final int count )
359        throws UnsupportedOperationException,
360            IllegalArgumentException,
361            ArithmeticException
362    {
363        int myValue = this.intValue();
364        myValue >>= count;
365        return this.setScalar( myValue );
366    }
367
368    @Override
369    public PRIMITIVE shiftRightExtendZero( final int count )
370        throws UnsupportedOperationException,
371            IllegalArgumentException,
372            ArithmeticException
373    {
374        int myValue = this.intValue();
375        myValue >>>= count;
376        return this.setScalar( myValue );
377    }
378
379    @Override
380    public final PRIMITIVE sum( final int aValue )
381        throws UnsupportedOperationException,
382            IllegalArgumentException,
383            ArithmeticException
384    {
385        final int result = this.intValue() + aValue;
386        return this.setScalar(result);
387    }
388
389    @Override
390    public final PRIMITIVE xor( final int aValue )
391        throws UnsupportedOperationException,
392            IllegalArgumentException,
393            ArithmeticException
394    {
395        final int result = this.intValue() ^ aValue;
396        return this.setScalar(result);
397    }
398}